]> git.mxchange.org Git - friendica.git/commitdiff
Merge pull request #6641 from nupplaphil/config_followup
authorHypolite Petovan <hypolite@mrpetovan.com>
Sun, 17 Feb 2019 22:56:31 +0000 (17:56 -0500)
committerGitHub <noreply@github.com>
Sun, 17 Feb 2019 22:56:31 +0000 (17:56 -0500)
Config FollowUp

84 files changed:
bin/auth_ejabberd.php
bin/console.php
bin/daemon.php
bin/worker.php
composer.json
composer.lock
include/api.php
index.php
src/App.php
src/Content/Text/BBCode.php
src/Content/Text/Markdown.php
src/Core/Addon.php
src/Core/Cache.php
src/Core/Config.php
src/Core/Config/AbstractDbaConfigAdapter.php [deleted file]
src/Core/Config/Adapter/AbstractDbaConfigAdapter.php [new file with mode: 0644]
src/Core/Config/Adapter/IConfigAdapter.php [new file with mode: 0644]
src/Core/Config/Adapter/IPConfigAdapter.php [new file with mode: 0644]
src/Core/Config/Adapter/JITConfigAdapter.php [new file with mode: 0644]
src/Core/Config/Adapter/JITPConfigAdapter.php [new file with mode: 0644]
src/Core/Config/Adapter/PreloadConfigAdapter.php [new file with mode: 0644]
src/Core/Config/Adapter/PreloadPConfigAdapter.php [new file with mode: 0644]
src/Core/Config/Cache/ConfigCache.php [new file with mode: 0644]
src/Core/Config/Cache/ConfigCacheLoader.php [new file with mode: 0644]
src/Core/Config/Cache/IConfigCache.php [new file with mode: 0644]
src/Core/Config/Cache/IPConfigCache.php [new file with mode: 0644]
src/Core/Config/ConfigCache.php [deleted file]
src/Core/Config/ConfigCacheLoader.php [deleted file]
src/Core/Config/Configuration.php [new file with mode: 0644]
src/Core/Config/IConfigAdapter.php [deleted file]
src/Core/Config/IConfigCache.php [deleted file]
src/Core/Config/IPConfigAdapter.php [deleted file]
src/Core/Config/IPConfigCache.php [deleted file]
src/Core/Config/JITConfigAdapter.php [deleted file]
src/Core/Config/JITPConfigAdapter.php [deleted file]
src/Core/Config/PConfiguration.php [new file with mode: 0644]
src/Core/Config/PreloadConfigAdapter.php [deleted file]
src/Core/Config/PreloadPConfigAdapter.php [deleted file]
src/Core/Console/AutomaticInstallation.php
src/Core/Console/Config.php
src/Core/Console/Typo.php
src/Core/Installer.php
src/Core/Logger.php
src/Core/PConfig.php
src/Core/Renderer.php
src/Core/Theme.php
src/Core/Worker.php
src/Database/DBA.php
src/Factory/ConfigFactory.php
src/Factory/DBFactory.php [new file with mode: 0644]
src/Factory/DependencyFactory.php [new file with mode: 0644]
src/Factory/LoggerFactory.php
src/Factory/ProfilerFactory.php [new file with mode: 0644]
src/Module/Install.php
src/Object/Image.php
src/Util/Network.php
src/Util/Profiler.php [new file with mode: 0644]
tests/DatabaseTest.php
tests/Util/AppMockTrait.php
tests/Util/DBStructureMockTrait.php
tests/include/ApiTest.php
tests/src/App/ModeTest.php
tests/src/BaseObjectTest.php
tests/src/Core/Cache/CacheTest.php
tests/src/Core/Cache/MemcacheCacheDriverTest.php
tests/src/Core/Cache/MemcachedCacheDriverTest.php
tests/src/Core/Cache/RedisCacheDriverTest.php
tests/src/Core/Config/Cache/ConfigCacheLoaderTest.php [new file with mode: 0644]
tests/src/Core/Config/Cache/ConfigCacheTest.php [new file with mode: 0644]
tests/src/Core/Config/ConfigCacheLoaderTest.php [deleted file]
tests/src/Core/Config/ConfigCacheTest.php [deleted file]
tests/src/Core/Config/ConfigurationTest.php [new file with mode: 0644]
tests/src/Core/Config/PConfigurationTest.php [new file with mode: 0644]
tests/src/Core/Console/AutomaticInstallationConsoleTest.php
tests/src/Core/Console/ConfigConsoleTest.php
tests/src/Core/Console/ConsoleTest.php
tests/src/Core/Lock/LockTest.php
tests/src/Core/Lock/MemcacheCacheLockDriverTest.php
tests/src/Core/Lock/MemcachedCacheLockDriverTest.php
tests/src/Core/Lock/RedisCacheLockDriverTest.php
tests/src/Core/Lock/SemaphoreLockDriverTest.php
tests/src/Database/DBATest.php
tests/src/Database/DBStructureTest.php
tests/src/Util/ProfilerTest.php [new file with mode: 0644]

index 11df438952a06e96ee700a7d6345cba1c90007d8..bf6d069d12bb58f1507f9d9ee6e0c14763c6e08e 100755 (executable)
  *
  */
 
-use Friendica\App;
-use Friendica\Core\Config;
 use Friendica\Factory;
-use Friendica\Util\BasePath;
 use Friendica\Util\ExAuth;
 
 if (sizeof($_SERVER["argv"]) == 0) {
@@ -54,12 +51,7 @@ chdir($directory);
 
 require dirname(__DIR__) . '/vendor/autoload.php';
 
-$basedir = BasePath::create(dirname(__DIR__), $_SERVER);
-$configLoader = new Config\ConfigCacheLoader($basedir);
-$config = Factory\ConfigFactory::createCache($configLoader);
-$logger = Factory\LoggerFactory::create('auth_ejabberd', $config);
-
-$a = new App($config, $logger);
+$a = Factory\DependencyFactory::setUp('auth_ejabbered', dirname(__DIR__));
 
 if ($a->getMode()->isNormal()) {
        $oAuth = new ExAuth();
index 9061824d875b0be10f8f1fad8aa94c1f883c55a0..410eabda094639db0d3d06a9a8eb41ec92220464 100755 (executable)
@@ -3,16 +3,9 @@
 
 require dirname(__DIR__) . '/vendor/autoload.php';
 
-use Friendica\Core\Config;
 use Friendica\Factory;
-use Friendica\Util\BasePath;
 
-$basedir = BasePath::create(dirname(__DIR__), $_SERVER);
-$configLoader = new Config\ConfigCacheLoader($basedir);
-$config = Factory\ConfigFactory::createCache($configLoader);
-$logger = Factory\LoggerFactory::create('console', $config);
-
-$a = new Friendica\App($config, $logger);
+$a = Factory\DependencyFactory::setUp('console', dirname(__DIR__));
 \Friendica\BaseObject::setApp($a);
 
 (new Friendica\Core\Console($argv))->execute();
index 5c014a92702429d58af4dfab1ac163597d34b95d..047bf71be77b4ac31dbea889098e5dd52dce8b5b 100755 (executable)
@@ -7,12 +7,11 @@
  * This script was taken from http://php.net/manual/en/function.pcntl-fork.php
  */
 
-use Friendica\App;
 use Friendica\Core\Config;
+use Friendica\Core\Logger;
 use Friendica\Core\Worker;
 use Friendica\Database\DBA;
 use Friendica\Factory;
-use Friendica\Util\BasePath;
 
 // Get options
 $shortopts = 'f';
@@ -33,12 +32,7 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
 
 require dirname(__DIR__) . '/vendor/autoload.php';
 
-$basedir = BasePath::create(dirname(__DIR__), $_SERVER);
-$configLoader = new Config\ConfigCacheLoader($basedir);
-$config = Factory\ConfigFactory::createCache($configLoader);
-$logger = Factory\LoggerFactory::create('daemon', $config);
-
-$a = new App($config, $logger);
+$a = Factory\DependencyFactory::setUp('daemon', dirname(__DIR__));
 
 if ($a->getMode()->isInstall()) {
        die("Friendica isn't properly installed yet.\n");
@@ -108,7 +102,7 @@ if ($mode == "stop") {
 
        unlink($pidfile);
 
-       $logger->notice("Worker daemon process was killed", ["pid" => $pid]);
+       Logger::notice("Worker daemon process was killed", ["pid" => $pid]);
 
        Config::set('system', 'worker_daemon_mode', false);
        die("Worker daemon process $pid was killed.\n");
@@ -118,7 +112,7 @@ if (!empty($pid) && posix_kill($pid, 0)) {
        die("Daemon process $pid is already running.\n");
 }
 
-$logger->notice('Starting worker daemon.', ["pid" => $pid]);
+Logger::notice('Starting worker daemon.', ["pid" => $pid]);
 
 if (!$foreground) {
        echo "Starting worker daemon.\n";
@@ -150,7 +144,7 @@ if (!$foreground) {
        file_put_contents($pidfile, $pid);
 
        // We lose the database connection upon forking
-       $a->loadDatabase();
+       Factory\DBFactory::init($a->getConfigCache(), $a->getProfiler(), $_SERVER);
 }
 
 Config::set('system', 'worker_daemon_mode', true);
@@ -166,7 +160,7 @@ $last_cron = 0;
 // Now running as a daemon.
 while (true) {
        if (!$do_cron && ($last_cron + $wait_interval) < time()) {
-               $logger->info('Forcing cron worker call.', ["pid" => $pid]);
+               Logger::info('Forcing cron worker call.', ["pid" => $pid]);
                $do_cron = true;
        }
 
@@ -180,7 +174,7 @@ while (true) {
                $last_cron = time();
        }
 
-       $logger->info("Sleeping", ["pid" => $pid]);
+       Logger::info("Sleeping", ["pid" => $pid]);
        $start = time();
        do {
                $seconds = (time() - $start);
@@ -197,10 +191,10 @@ while (true) {
 
        if ($timeout) {
                $do_cron = true;
-               $logger->info("Woke up after $wait_interval seconds.", ["pid" => $pid, 'sleep' => $wait_interval]);
+               Logger::info("Woke up after $wait_interval seconds.", ["pid" => $pid, 'sleep' => $wait_interval]);
        } else {
                $do_cron = false;
-               $logger->info("Worker jobs are calling to be forked.", ["pid" => $pid]);
+               Logger::info("Worker jobs are calling to be forked.", ["pid" => $pid]);
        }
 }
 
index 553e9849774fe307e5f1535b9c090809ce043e80..c7174d81e1813ea0e246e2435c0132a7bdb8249a 100755 (executable)
@@ -10,7 +10,6 @@ use Friendica\Core\Config;
 use Friendica\Core\Update;
 use Friendica\Core\Worker;
 use Friendica\Factory;
-use Friendica\Util\BasePath;
 
 // Get options
 $shortopts = 'sn';
@@ -31,12 +30,7 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
 
 require dirname(__DIR__) . '/vendor/autoload.php';
 
-$basedir = BasePath::create(dirname(__DIR__), $_SERVER);
-$configLoader = new Config\ConfigCacheLoader($basedir);
-$config = Factory\ConfigFactory::createCache($configLoader);
-$logger = Factory\LoggerFactory::create('worker', $config);
-
-$a = new App($config, $logger);
+$a = Factory\DependencyFactory::setUp('worker', dirname(__DIR__));
 
 // Check the database structure and possibly fixes it
 Update::check($a->getBasePath(), true);
index 39d9358926ed905cfe06de144dccb48c8331d0b0..3638a9495921562dd660fb4ef0b9a2c995857d76 100644 (file)
                "lightopenid/lightopenid": "dev-master",
                "michelf/php-markdown": "^1.7",
                "mobiledetect/mobiledetectlib": "2.8.*",
+               "monolog/monolog": "^1.24",
                "paragonie/random_compat": "^2.0",
-               "pear/Text_LanguageDetect": "1.*",
+               "pear/text_languagedetect": "1.*",
+               "psr/container": "^1.0",
                "seld/cli-prompt": "^1.0",
                "smarty/smarty": "^3.1",
                "fxp/composer-asset-plugin": "~1.3",
                "bower-asset/base64": "^1.0",
-               "bower-asset/Chart-js": "^2.7",
+               "bower-asset/chart-js": "^2.7",
                "bower-asset/perfect-scrollbar": "^0.6",
                "bower-asset/vue": "^2.5",
                "npm-asset/jquery": "^2.0",
@@ -49,8 +51,7 @@
                "npm-asset/jgrowl": "^1.4",
                "npm-asset/fullcalendar": "^3.0.1",
                "npm-asset/cropperjs": "1.2.2",
-               "npm-asset/imagesloaded": "4.1.4",
-               "monolog/monolog": "^1.24"
+               "npm-asset/imagesloaded": "4.1.4"
        },
        "repositories": [
                {
@@ -96,7 +97,7 @@
                "phpunit/dbunit": "^2.0",
                "phpdocumentor/reflection-docblock": "^3.0.2",
                "phpunit/php-token-stream": "^1.4.2",
-               "mikey179/vfsStream": "^1.6",
+               "mikey179/vfsstream": "^1.6",
                "mockery/mockery": "^1.2",
                "johnkary/phpunit-speedtrap": "1.1"
        },
index f91b833de74ad1b5ae902809377a90ad3d032fa3..e554b119992198d1d35d8ef65eaf31c88d7ab368 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "b944adfb6ede89430ba3b7e9ebb45acb",
+    "content-hash": "19fabb14e0dd5d806ef841e51d5f6a0b",
     "packages": [
         {
             "name": "asika/simple-console",
             ],
             "time": "2016-08-06T20:24:11+00:00"
         },
+        {
+            "name": "psr/container",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/container.git",
+                "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+                "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Container\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common Container Interface (PHP FIG PSR-11)",
+            "homepage": "https://github.com/php-fig/container",
+            "keywords": [
+                "PSR-11",
+                "container",
+                "container-interface",
+                "container-interop",
+                "psr"
+            ],
+            "time": "2017-02-14T16:28:37+00:00"
+        },
         {
             "name": "psr/http-message",
             "version": "1.0.1",
                 "testing",
                 "xunit"
             ],
+            "abandoned": true,
             "time": "2016-12-02T14:39:14+00:00"
         },
         {
index 052d32b17b1f8d788db0d7c65559febeb6cd3aa1..13ff75bdb50a81f1f602ea70e445ccae9b05b6c6 100644 (file)
@@ -326,69 +326,7 @@ function api_call(App $a)
 
                                Logger::info(API_LOG_PREFIX . 'username {username}', ['module' => 'api', 'action' => 'call', 'username' => $a->user['username'], 'duration' => round($duration, 2)]);
 
-                               if (Config::get("system", "profiler")) {
-                                       $duration = microtime(true)-$a->performance["start"];
-
-                                       /// @TODO round() really everywhere?
-                                       Logger::debug(
-                                               API_LOG_PREFIX . 'performance',
-                                               [
-                                                       'module' => 'api',
-                                                       'action' => 'call',
-                                                       'database_read' => round($a->performance["database"] - $a->performance["database_write"], 3),
-                                                       'database_write' => round($a->performance["database_write"], 3),
-                                                       'cache_read' => round($a->performance["cache"], 3),
-                                                       'cache_write' => round($a->performance["cache_write"], 3),
-                                                       'network_io' => round($a->performance["network"], 2),
-                                                       'file_io' => round($a->performance["file"], 2),
-                                                       'other_io' => round($duration - ($a->performance["database"]
-                                                                       + $a->performance["cache"] + $a->performance["cache_write"]
-                                                                       + $a->performance["network"] + $a->performance["file"]), 2),
-                                                       'total' => round($duration, 2)
-                                               ]
-                                       );
-
-                                       if (Config::get("rendertime", "callstack")) {
-                                               $o = "Database Read:\n";
-                                               foreach ($a->callstack["database"] as $func => $time) {
-                                                       $time = round($time, 3);
-                                                       if ($time > 0) {
-                                                               $o .= $func . ": " . $time . "\n";
-                                                       }
-                                               }
-                                               $o .= "\nDatabase Write:\n";
-                                               foreach ($a->callstack["database_write"] as $func => $time) {
-                                                       $time = round($time, 3);
-                                                       if ($time > 0) {
-                                                               $o .= $func . ": " . $time . "\n";
-                                                       }
-                                               }
-
-                                               $o = "Cache Read:\n";
-                                               foreach ($a->callstack["cache"] as $func => $time) {
-                                                       $time = round($time, 3);
-                                                       if ($time > 0) {
-                                                               $o .= $func . ": " . $time . "\n";
-                                                       }
-                                               }
-                                               $o .= "\nCache Write:\n";
-                                               foreach ($a->callstack["cache_write"] as $func => $time) {
-                                                       $time = round($time, 3);
-                                                       if ($time > 0) {
-                                                               $o .= $func . ": " . $time . "\n";
-                                                       }
-                                               }
-
-                                               $o .= "\nNetwork:\n";
-                                               foreach ($a->callstack["network"] as $func => $time) {
-                                                       $time = round($time, 3);
-                                                       if ($time > 0) {
-                                                               $o .= $func . ": " . $time . "\n";
-                                                       }
-                                               }
-                                               Logger::debug(API_LOG_PREFIX . $o, ['module' => 'api', 'action' => 'call']);
-                                       }
-                               }
+                               $a->getProfiler()->saveLog($a->getLogger(), API_LOG_PREFIX . 'performance');
 
                                if (false === $return) {
                                        /*
index 7e7396785f5993c7b17f7a1e74870b7be5b4afcd..47264362c52edf42a0430fda678c02ed55b27047 100644 (file)
--- a/index.php
+++ b/index.php
@@ -4,10 +4,7 @@
  * Friendica
  */
 
-use Friendica\App;
-use Friendica\Core\Config;
 use Friendica\Factory;
-use Friendica\Util\BasePath;
 
 if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
        die('Vendor path not found. Please execute "bin/composer.phar --no-dev install" on the command line in the web root.');
@@ -15,13 +12,6 @@ if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
 
 require __DIR__ . '/vendor/autoload.php';
 
-$basedir = BasePath::create(__DIR__, $_SERVER);
-$configLoader = new Config\ConfigCacheLoader($basedir);
-$config = Factory\ConfigFactory::createCache($configLoader);
-$logger = Factory\LoggerFactory::create('index', $config);
-
-// We assume that the index.php is called by a frontend process
-// The value is set to "true" by default in App
-$a = new App($config, $logger, false);
+$a = Factory\DependencyFactory::setUp('index', __DIR__, true);
 
 $a->runFrontend();
index b9e22dd1b53034d036adee442967045eb1591e98..ca2b6dfc21770a994581f64d0e82b1fce76cd9f8 100644 (file)
@@ -8,11 +8,12 @@ use Detection\MobileDetect;
 use DOMDocument;
 use DOMXPath;
 use Exception;
-use Friendica\Core\Config\ConfigCache;
-use Friendica\Core\Config\ConfigCacheLoader;
+use Friendica\Core\Config\Cache\ConfigCacheLoader;
+use Friendica\Core\Config\Cache\IConfigCache;
+use Friendica\Core\Config\Configuration;
 use Friendica\Database\DBA;
-use Friendica\Factory\ConfigFactory;
 use Friendica\Network\HTTPException\InternalServerErrorException;
+use Friendica\Util\Profiler;
 use Psr\Log\LoggerInterface;
 
 /**
@@ -53,8 +54,6 @@ class App
        public $identities;
        public $is_mobile = false;
        public $is_tablet = false;
-       public $performance = [];
-       public $callstack = [];
        public $theme_info = [];
        public $category;
        // Allow themes to control internal parameters
@@ -110,23 +109,28 @@ class App
        public $mobileDetect;
 
        /**
-        * @var LoggerInterface The current logger of this App
+        * @var Configuration The config
+        */
+       private $config;
+
+       /**
+        * @var LoggerInterface The logger
         */
        private $logger;
 
        /**
-        * @var ConfigCache The cached config
+        * @var Profiler The profiler of this app
         */
-       private $config;
+       private $profiler;
 
        /**
         * Returns the current config cache of this node
         *
-        * @return ConfigCache
+        * @return IConfigCache
         */
-       public function getConfig()
+       public function getConfigCache()
        {
-               return $this->config;
+               return $this->config->getCache();
        }
 
        /**
@@ -139,6 +143,26 @@ class App
                return $this->basePath;
        }
 
+       /**
+        * The Logger of this app
+        *
+        * @return LoggerInterface
+        */
+       public function getLogger()
+       {
+               return $this->logger;
+       }
+
+       /**
+        * The profiler of this app
+        *
+        * @return Profiler
+        */
+       public function getProfiler()
+       {
+               return $this->profiler;
+       }
+
        /**
         * Register a stylesheet file path to be included in the <head> tag of every page.
         * Inclusion is done in App->initHead().
@@ -181,16 +205,18 @@ class App
        /**
         * @brief App constructor.
         *
-        * @param ConfigCache      $config    The Cached Config
-        * @param LoggerInterface  $logger    Logger of this application
+        * @param Configuration    $config    The Configuration
+        * @param LoggerInterface  $logger    The current app logger
+        * @param Profiler         $profiler  The profiler of this application
         * @param bool             $isBackend Whether it is used for backend or frontend (Default true=backend)
         *
         * @throws Exception if the Basepath is not usable
         */
-       public function __construct(ConfigCache $config, LoggerInterface $logger, $isBackend = true)
+       public function __construct(Configuration $config, LoggerInterface $logger, Profiler $profiler, $isBackend = true)
        {
-               $this->config   = $config;
                $this->logger   = $logger;
+               $this->config   = $config;
+               $this->profiler = $profiler;
                $this->basePath = $this->config->get('system', 'basepath');
 
                if (!Core\System::isDirectoryUsable($this->basePath, false)) {
@@ -203,26 +229,7 @@ class App
                $this->checkBackend($isBackend);
                $this->checkFriendicaApp();
 
-               $this->performance['start'] = microtime(true);
-               $this->performance['database'] = 0;
-               $this->performance['database_write'] = 0;
-               $this->performance['cache'] = 0;
-               $this->performance['cache_write'] = 0;
-               $this->performance['network'] = 0;
-               $this->performance['file'] = 0;
-               $this->performance['rendering'] = 0;
-               $this->performance['parser'] = 0;
-               $this->performance['marktime'] = 0;
-               $this->performance['markstart'] = microtime(true);
-
-               $this->callstack['database'] = [];
-               $this->callstack['database_write'] = [];
-               $this->callstack['cache'] = [];
-               $this->callstack['cache_write'] = [];
-               $this->callstack['network'] = [];
-               $this->callstack['file'] = [];
-               $this->callstack['rendering'] = [];
-               $this->callstack['parser'] = [];
+               $this->profiler->reset();
 
                $this->mode = new App\Mode($this->basePath);
 
@@ -341,52 +348,20 @@ class App
                return $this->mode;
        }
 
-       /**
-        * Returns the Logger of the Application
-        *
-        * @return LoggerInterface The Logger
-        * @throws InternalServerErrorException when the logger isn't created
-        */
-       public function getLogger()
-       {
-               if (empty($this->logger)) {
-                       throw new InternalServerErrorException('Logger of the Application is not defined');
-               }
-
-               return $this->logger;
-       }
-
        /**
         * Reloads the whole app instance
         */
        public function reload()
        {
-               Core\Config::init($this->config);
-               Core\PConfig::init($this->config);
-
-               $this->loadDatabase();
-
-               $this->getMode()->determine($this->basePath);
-
                $this->determineURLPath();
 
-               if ($this->getMode()->has(App\Mode::DBCONFIGAVAILABLE)) {
-                       $adapterType = $this->config->get('system', 'config_adapter');
-                       $adapter = ConfigFactory::createConfig($adapterType, $this->config);
-                       Core\Config::setAdapter($adapter);
-                       $adapterP = ConfigFactory::createPConfig($adapterType, $this->config);
-                       Core\PConfig::setAdapter($adapterP);
-                       Core\Config::load();
-               }
-
-               // again because DB-config could change the config
                $this->getMode()->determine($this->basePath);
 
                if ($this->getMode()->has(App\Mode::DBAVAILABLE)) {
                        Core\Hook::loadHooks();
                        $loader = new ConfigCacheLoader($this->basePath);
                        Core\Hook::callAll('load_config', $loader);
-                       $this->config->loadConfigArray($loader->loadCoreConfig('addon'), true);
+                       $this->config->getCache()->load($loader->loadCoreConfig('addon'), true);
                }
 
                $this->loadDefaultTimezone();
@@ -394,8 +369,6 @@ class App
                Core\L10n::init();
 
                $this->process_id = Core\System::processID('log');
-
-               Core\Logger::setLogger($this->logger);
        }
 
        /**
@@ -456,49 +429,6 @@ class App
                }
        }
 
-       public function loadDatabase()
-       {
-               if (DBA::connected()) {
-                       return;
-               }
-
-               $db_host = $this->config->get('database', 'hostname');
-               $db_user = $this->config->get('database', 'username');
-               $db_pass = $this->config->get('database', 'password');
-               $db_data = $this->config->get('database', 'database');
-               $charset = $this->config->get('database', 'charset');
-
-               // Use environment variables for mysql if they are set beforehand
-               if (!empty(getenv('MYSQL_HOST'))
-                       && !empty(getenv('MYSQL_USERNAME') || !empty(getenv('MYSQL_USER')))
-                       && getenv('MYSQL_PASSWORD') !== false
-                       && !empty(getenv('MYSQL_DATABASE')))
-               {
-                       $db_host = getenv('MYSQL_HOST');
-                       if (!empty(getenv('MYSQL_PORT'))) {
-                               $db_host .= ':' . getenv('MYSQL_PORT');
-                       }
-                       if (!empty(getenv('MYSQL_USERNAME'))) {
-                               $db_user = getenv('MYSQL_USERNAME');
-                       } else {
-                               $db_user = getenv('MYSQL_USER');
-                       }
-                       $db_pass = (string) getenv('MYSQL_PASSWORD');
-                       $db_data = getenv('MYSQL_DATABASE');
-               }
-
-               $stamp1 = microtime(true);
-
-               if (DBA::connect($this->config, $db_host, $db_user, $db_pass, $db_data, $charset)) {
-                       // Loads DB_UPDATE_VERSION constant
-                       Database\DBStructure::definition($this->basePath, false);
-               }
-
-               unset($db_host, $db_user, $db_pass, $db_data, $charset);
-
-               $this->saveTimestamp($stamp1, 'network');
-       }
-
        public function getScheme()
        {
                return $this->scheme;
@@ -740,41 +670,6 @@ class App
                }
        }
 
-       /**
-        * Saves a timestamp for a value - f.e. a call
-        * Necessary for profiling Friendica
-        *
-        * @param int $timestamp the Timestamp
-        * @param string $value A value to profile
-        */
-       public function saveTimestamp($timestamp, $value)
-       {
-               $profiler = $this->config->get('system', 'profiler');
-
-               if (!isset($profiler) || !$profiler) {
-                       return;
-               }
-
-               $duration = (float) (microtime(true) - $timestamp);
-
-               if (!isset($this->performance[$value])) {
-                       // Prevent ugly E_NOTICE
-                       $this->performance[$value] = 0;
-               }
-
-               $this->performance[$value] += (float) $duration;
-               $this->performance['marktime'] += (float) $duration;
-
-               $callstack = Core\System::callstack();
-
-               if (!isset($this->callstack[$value][$callstack])) {
-                       // Prevent ugly E_NOTICE
-                       $this->callstack[$value][$callstack] = 0;
-               }
-
-               $this->callstack[$value][$callstack] += (float) $duration;
-       }
-
        /**
         * Returns the current UserAgent as a String
         *
@@ -1225,7 +1120,7 @@ class App
                if (!$this->isBackend()) {
                        $stamp1 = microtime(true);
                        session_start();
-                       $this->saveTimestamp($stamp1, 'parser');
+                       $this->profiler->saveTimestamp($stamp1, 'parser', Core\System::callstack());
                        Core\L10n::setSessionVariable();
                        Core\L10n::setLangFromSession();
                } else {
index a8b5ec2025546e7ffa0e694597d2f38524ccd8b1..e9b5f98d0b496deb0f6839f78a66b4b0e986a896 100644 (file)
@@ -1027,7 +1027,7 @@ class BBCode extends BaseObject
                        @curl_exec($ch);
                        $curl_info = @curl_getinfo($ch);
 
-                       $a->saveTimestamp($stamp1, "network");
+                       $a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack());
 
                        if (substr($curl_info["content_type"], 0, 6) == "image/") {
                                $text = "[url=" . $match[1] . "]" . $match[1] . "[/url]";
@@ -1086,7 +1086,7 @@ class BBCode extends BaseObject
                        @curl_exec($ch);
                        $curl_info = @curl_getinfo($ch);
 
-                       $a->saveTimestamp($stamp1, "network");
+                       $a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack());
 
                        // if its a link to a picture then embed this picture
                        if (substr($curl_info["content_type"], 0, 6) == "image/") {
@@ -1915,7 +1915,7 @@ class BBCode extends BaseObject
                // unmask the special chars back to HTML
                $text = str_replace(['&\_lt\_;', '&\_gt\_;', '&\_amp\_;'], ['&lt;', '&gt;', '&amp;'], $text);
 
-               $a->saveTimestamp($stamp1, "parser");
+               $a->getProfiler()->saveTimestamp($stamp1, "parser", System::callstack());
 
                // Libertree has a problem with escaped hashtags.
                $text = str_replace(['\#'], ['#'], $text);
index ceb5b043b3065ba045c27891fc0138df916afd31..e3e2cd3ac957750e56f04205179611a3038aac72 100644 (file)
@@ -7,6 +7,7 @@
 namespace Friendica\Content\Text;
 
 use Friendica\BaseObject;
+use Friendica\Core\System;
 use Friendica\Model\Contact;
 use Michelf\MarkdownExtra;
 
@@ -36,7 +37,7 @@ class Markdown extends BaseObject
                $html = $MarkdownParser->transform($text);
                $html = preg_replace('/<a(.*?)href="#/is', '<a$1href="' . ltrim($_SERVER['REQUEST_URI'], '/') . '#', $html);
 
-               self::getApp()->saveTimestamp($stamp1, "parser");
+               self::getApp()->getProfiler()->saveTimestamp($stamp1, "parser", System::callstack());
 
                return $html;
        }
index 6697a44aea13bd60b480fa0cb067d4fa5e9f2be5..7957e08350efefb0cd68c39287b4bd3c7a903fc4 100644 (file)
@@ -219,7 +219,7 @@ class Addon extends BaseObject
 
                $stamp1 = microtime(true);
                $f = file_get_contents("addon/$addon/$addon.php");
-               $a->saveTimestamp($stamp1, "file");
+               $a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
 
                $r = preg_match("|/\*.*\*/|msU", $f, $m);
 
index 39c29566d3560df5c5d0ede30804c42ce10798d0..cadb2444b50e4debee4b9eff7a9f55d6e47f1d60 100644 (file)
@@ -63,7 +63,7 @@ class Cache extends \Friendica\BaseObject
 
                $return = self::getDriver()->getAllKeys($prefix);
 
-               self::getApp()->saveTimestamp($time, 'cache');
+               self::getApp()->getProfiler()->saveTimestamp($time, 'cache', System::callstack());
 
                return $return;
        }
@@ -82,7 +82,7 @@ class Cache extends \Friendica\BaseObject
 
                $return = self::getDriver()->get($key);
 
-               self::getApp()->saveTimestamp($time, 'cache');
+               self::getApp()->getProfiler()->saveTimestamp($time, 'cache', System::callstack());
 
                return $return;
        }
@@ -105,7 +105,7 @@ class Cache extends \Friendica\BaseObject
 
                $return = self::getDriver()->set($key, $value, $duration);
 
-               self::getApp()->saveTimestamp($time, 'cache_write');
+               self::getApp()->getProfiler()->saveTimestamp($time, 'cache_write', System::callstack());
 
                return $return;
        }
@@ -124,7 +124,7 @@ class Cache extends \Friendica\BaseObject
 
                $return = self::getDriver()->delete($key);
 
-               self::getApp()->saveTimestamp($time, 'cache_write');
+               self::getApp()->getProfiler()->saveTimestamp($time, 'cache_write', System::callstack());
 
                return $return;
        }
index 559ee83ece57e08b8bfedb53d94510b082606459..4bf9c5b11d2d4aa96495516edfc38dc94c098f25 100644 (file)
@@ -8,10 +8,6 @@
  */
 namespace Friendica\Core;
 
-use Friendica\Core\Config\ConfigCache;
-use Friendica\Core\Config\IConfigAdapter;
-use Friendica\Core\Config\IConfigCache;
-
 /**
  * @brief Arbitrary system configuration storage
  *
@@ -22,116 +18,76 @@ use Friendica\Core\Config\IConfigCache;
 class Config
 {
        /**
-        * @var Config\IConfigAdapter|null
+        * @var Config\Configuration
         */
-       private static $adapter;
+       private static $config;
 
        /**
-        * @var Config\IConfigCache
-        */
-       private static $cache;
-
-       /**
-        * Initialize the config with only the cache
+        * Initialize the config
         *
-        * @param Config\IConfigCache $cache  The configuration cache
+        * @param Config\Configuration $config
         */
-       public static function init(Config\IConfigCache $cache)
+       public static function init(Config\Configuration $config)
        {
-               self::$cache  = $cache;
-       }
-
-       /**
-        * Add the adapter for DB-backend
-        *
-        * @param Config\IConfigAdapter $adapter
-        */
-       public static function setAdapter(Config\IConfigAdapter $adapter)
-       {
-               self::$adapter = $adapter;
+               self::$config = $config;
        }
 
        /**
         * @brief Loads all configuration values of family into a cached storage.
         *
-        * All configuration values of the system are stored in the cache ( @see IConfigCache )
-        *
-        * @param string $family The category of the configuration value
+        * @param string $cat The category of the configuration value
         *
         * @return void
         */
-       public static function load($family = "config")
+       public static function load($cat = "config")
        {
-               if (!isset(self::$adapter) || !self::$adapter->isConnected()) {
-                       return;
-               }
-
-               self::$adapter->load($family);
+               self::$config->load($cat);
        }
 
        /**
         * @brief Get a particular user's config variable given the category name
         * ($family) and a key.
         *
-        * Get a particular config value from the given category ($family)
-        * and the $key from a cached storage either from the self::$adapter
-        * (@see IConfigAdapter ) or from the static::$cache (@see IConfigCache ).
-        *
-        * @param string  $family        The category of the configuration value
+        * @param string  $cat        The category of the configuration value
         * @param string  $key           The configuration key to query
         * @param mixed   $default_value optional, The value to return if key is not set (default: null)
         * @param boolean $refresh       optional, If true the config is loaded from the db and not from the cache (default: false)
         *
         * @return mixed Stored value or null if it does not exist
         */
-       public static function get($family, $key, $default_value = null, $refresh = false)
+       public static function get($cat, $key, $default_value = null, $refresh = false)
        {
-               if (!isset(self::$adapter) || !self::$adapter->isConnected()) {
-                       return self::$cache->get($family, $key, $default_value);
-               }
-
-               return self::$adapter->get($family, $key, $default_value, $refresh);
+               return self::$config->get($cat, $key, $default_value, $refresh);
        }
 
        /**
         * @brief Sets a configuration value for system config
         *
-        * Stores a config value ($value) in the category ($family) under the key ($key)
+        * Stores a config value ($value) in the category ($cat) under the key ($key)
         *
         * Note: Please do not store booleans - convert to 0/1 integer values!
         *
-        * @param string $family The category of the configuration value
+        * @param string $cat The category of the configuration value
         * @param string $key    The configuration key to set
         * @param mixed  $value  The value to store
         *
         * @return bool Operation success
         */
-       public static function set($family, $key, $value)
+       public static function set($cat, $key, $value)
        {
-               if (!isset(self::$adapter) || !self::$adapter->isConnected()) {
-                       return self::$cache->set($family, $key, $value);
-               }
-
-               return self::$adapter->set($family, $key, $value);
+               return self::$config->set($cat, $key, $value);
        }
 
        /**
         * @brief Deletes the given key from the system configuration.
         *
-        * Removes the configured value from the stored cache in self::$config
-        * (@see ConfigCache ) and removes it from the database (@see IConfigAdapter ).
-        *
-        * @param string $family The category of the configuration value
+        * @param string $cat The category of the configuration value
         * @param string $key    The configuration key to delete
         *
-        * @return mixed
+        * @return bool
         */
-       public static function delete($family, $key)
+       public static function delete($cat, $key)
        {
-               if (!isset(self::$adapter) || !self::$adapter->isConnected()) {
-                       self::$cache->delete($family, $key);
-               }
-
-               return self::$adapter->delete($family, $key);
+               return self::$config->delete($cat, $key);
        }
 }
diff --git a/src/Core/Config/AbstractDbaConfigAdapter.php b/src/Core/Config/AbstractDbaConfigAdapter.php
deleted file mode 100644 (file)
index bae7512..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-<?php
-
-namespace Friendica\Core\Config;
-
-abstract class AbstractDbaConfigAdapter
-{
-       /** @var bool */
-       protected $connected = true;
-
-       public function isConnected()
-       {
-               return $this->connected;
-       }
-}
diff --git a/src/Core/Config/Adapter/AbstractDbaConfigAdapter.php b/src/Core/Config/Adapter/AbstractDbaConfigAdapter.php
new file mode 100644 (file)
index 0000000..770dfd2
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+
+namespace Friendica\Core\Config\Adapter;
+
+use Friendica\Database\DBA;
+
+abstract class AbstractDbaConfigAdapter
+{
+       /** @var bool */
+       protected $connected = true;
+
+       public function __construct()
+       {
+               $this->connected = DBA::connected();
+       }
+
+       public function isConnected()
+       {
+               return $this->connected;
+       }
+}
diff --git a/src/Core/Config/Adapter/IConfigAdapter.php b/src/Core/Config/Adapter/IConfigAdapter.php
new file mode 100644 (file)
index 0000000..21cd9a4
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+
+namespace Friendica\Core\Config\Adapter;
+
+/**
+ *
+ * @author Hypolite Petovan <hypolite@mrpetovan.com>
+ */
+interface IConfigAdapter
+{
+       /**
+        * Loads all configuration values and returns the loaded category as an array.
+        *
+        * @param string  $cat The category of the configuration values to load
+        *
+        * @return array
+        */
+       public function load($cat = "config");
+
+       /**
+        * Get a particular system-wide config variable given the category name
+        * ($family) and a key.
+        *
+        * @param string  $cat The category of the configuration value
+        * @param string  $key The configuration key to query
+        *
+        * @return mixed Stored value or "!<unset>!" if it does not exist
+        */
+       public function get($cat, $key);
+
+       /**
+        * Stores a config value ($value) in the category ($family) under the key ($key).
+        *
+        * Note: Please do not store booleans - convert to 0/1 integer values!
+        *
+        * @param string $cat   The category of the configuration value
+        * @param string $key   The configuration key to set
+        * @param mixed  $value The value to store
+        *
+        * @return bool Operation success
+        */
+       public function set($cat, $key, $value);
+
+       /**
+        * Removes the configured value from the stored cache
+        * and removes it from the database.
+        *
+        * @param string $cat The category of the configuration value
+        * @param string $key   The configuration key to delete
+        *
+        * @return mixed
+        */
+       public function delete($cat, $key);
+
+       /**
+        * Checks, if the current adapter is connected to the backend
+        *
+        * @return bool
+        */
+       public function isConnected();
+
+       /**
+        * Checks, if a config key ($key) in the category ($cat) is already loaded.
+        *
+        * @param string $cat The configuration category
+        * @param string $key The configuration key
+        *
+        * @return bool
+        */
+       public function isLoaded($cat, $key);
+}
diff --git a/src/Core/Config/Adapter/IPConfigAdapter.php b/src/Core/Config/Adapter/IPConfigAdapter.php
new file mode 100644 (file)
index 0000000..8e6c050
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+namespace Friendica\Core\Config\Adapter;
+
+/**
+ *
+ * @author benlo
+ */
+interface IPConfigAdapter
+{
+       /**
+        * Loads all configuration values of a user's config family and returns the loaded category as an array.
+        *
+        * @param string $uid The user_id
+        * @param string $cat The category of the configuration value
+        *
+        * @return array
+        */
+       public function load($uid, $cat);
+
+       /**
+        * Get a particular user's config variable given the category name
+        * ($family) and a key.
+        *
+        * @param string  $uid           The user_id
+        * @param string  $cat           The category of the configuration value
+        * @param string  $key           The configuration key to query
+        *
+        * @return mixed Stored value or "!<unset>!" if it does not exist
+        */
+       public function get($uid, $cat, $key);
+
+       /**
+        * Stores a config value ($value) in the category ($family) under the key ($key)
+        * for the user_id $uid.
+        *
+        * @note Please do not store booleans - convert to 0/1 integer values!
+        *
+        * @param string $uid   The user_id
+        * @param string $cat   The category of the configuration value
+        * @param string $key   The configuration key to set
+        * @param string $value The value to store
+        *
+        * @return bool Operation success
+        */
+       public function set($uid, $cat, $key, $value);
+
+       /**
+        * Removes the configured value from the stored cache
+        * and removes it from the database.
+        *
+        * @param string $uid The user_id
+        * @param string $cat The category of the configuration value
+        * @param string $key The configuration key to delete
+        *
+        * @return bool
+        */
+       public function delete($uid, $cat, $key);
+
+       /**
+        * Checks, if the current adapter is connected to the backend
+        *
+        * @return bool
+        */
+       public function isConnected();
+
+       /**
+        * Checks, if a config key ($key) in the category ($cat) is already loaded for the user_id $uid.
+        *
+        * @param string $uid The user_id
+        * @param string $cat The configuration category
+        * @param string $key The configuration key
+        *
+        * @return bool
+        */
+       public function isLoaded($uid, $cat, $key);
+}
diff --git a/src/Core/Config/Adapter/JITConfigAdapter.php b/src/Core/Config/Adapter/JITConfigAdapter.php
new file mode 100644 (file)
index 0000000..9521177
--- /dev/null
@@ -0,0 +1,135 @@
+<?php
+namespace Friendica\Core\Config\Adapter;
+
+use Friendica\Database\DBA;
+
+/**
+ * JustInTime Configuration Adapter
+ *
+ * Default Config Adapter. Provides the best performance for pages loading few configuration variables.
+ *
+ * @author Hypolite Petovan <hypolite@mrpetovan.com>
+ */
+class JITConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAdapter
+{
+       private $in_db;
+
+       /**
+        * {@inheritdoc}
+        */
+       public function load($cat = "config")
+       {
+               $return = [];
+
+               if (!$this->isConnected()) {
+                       return $return;
+               }
+
+               // We don't preload "system" anymore.
+               // This reduces the number of database reads a lot.
+               if ($cat === 'system') {
+                       return $return;
+               }
+
+               $configs = DBA::select('config', ['v', 'k'], ['cat' => $cat]);
+               while ($config = DBA::fetch($configs)) {
+                       $key = $config['k'];
+
+                       $return[$key] = $config['v'];
+                       $this->in_db[$cat][$key] = true;
+               }
+               DBA::close($configs);
+
+               return [$cat => $config];
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function get($cat, $key)
+       {
+               if (!$this->isConnected()) {
+                       return '!<unset>!';
+               }
+
+               $config = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $key]);
+               if (DBA::isResult($config)) {
+                       // manage array value
+                       $value = (preg_match("|^a:[0-9]+:{.*}$|s", $config['v']) ? unserialize($config['v']) : $config['v']);
+
+                       $this->in_db[$cat][$key] = true;
+                       return $value;
+               } else {
+
+                       $this->in_db[$cat][$key] = false;
+                       return '!<unset>!';
+               }
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function set($cat, $key, $value)
+       {
+               if (!$this->isConnected()) {
+                       return false;
+               }
+
+               // We store our setting values in a string variable.
+               // So we have to do the conversion here so that the compare below works.
+               // The exception are array values.
+               $dbvalue = (!is_array($value) ? (string)$value : $value);
+
+               $stored = $this->get($cat, $key);
+
+               if (!isset($this->in_db[$cat])) {
+                       $this->in_db[$cat] = [];
+               }
+               if (!isset($this->in_db[$cat][$key])) {
+                       $this->in_db[$cat][$key] = false;
+               }
+
+               if (($stored === $dbvalue) && $this->in_db[$cat][$key]) {
+                       return true;
+               }
+
+               // manage array value
+               $dbvalue = (is_array($value) ? serialize($value) : $dbvalue);
+
+               $result = DBA::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $key], true);
+
+               $this->in_db[$cat][$key] = $result;
+
+               return $result;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function delete($cat, $key)
+       {
+               if (!$this->isConnected()) {
+                       return false;
+               }
+
+               if (isset($this->cache[$cat][$key])) {
+                       unset($this->in_db[$cat][$key]);
+               }
+
+               $result = DBA::delete('config', ['cat' => $cat, 'k' => $key]);
+
+               return $result;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function isLoaded($cat, $key)
+       {
+               if (!$this->isConnected()) {
+                       return false;
+               }
+
+               return (isset($this->in_db[$cat][$key])) && $this->in_db[$cat][$key];
+       }
+}
diff --git a/src/Core/Config/Adapter/JITPConfigAdapter.php b/src/Core/Config/Adapter/JITPConfigAdapter.php
new file mode 100644 (file)
index 0000000..c5f3a38
--- /dev/null
@@ -0,0 +1,138 @@
+<?php
+namespace Friendica\Core\Config\Adapter;
+
+use Friendica\Database\DBA;
+
+/**
+ * JustInTime User Configuration Adapter
+ *
+ * Default PConfig Adapter. Provides the best performance for pages loading few configuration variables.
+ *
+ * @author Hypolite Petovan <hypolite@mrpetovan.com>
+ */
+class JITPConfigAdapter extends AbstractDbaConfigAdapter implements IPConfigAdapter
+{
+       private $in_db;
+
+       /**
+        * {@inheritdoc}
+        */
+       public function load($uid, $cat)
+       {
+               $return = [];
+
+               if (!$this->isConnected()) {
+                       return $return;
+               }
+
+               $pconfigs = DBA::select('pconfig', ['v', 'k'], ['cat' => $cat, 'uid' => $uid]);
+               if (DBA::isResult($pconfigs)) {
+                       while ($pconfig = DBA::fetch($pconfigs)) {
+                               $key = $pconfig['k'];
+
+                               $return[$key] = $pconfig['v'];
+
+                               $this->in_db[$uid][$cat][$key] = true;
+                       }
+               } else if ($cat != 'config') {
+                       // Negative caching
+                       $return = "!<unset>!";
+               }
+               DBA::close($pconfigs);
+
+               return [$cat => $return];
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function get($uid, $cat, $key)
+       {
+               if (!$this->isConnected()) {
+                       return '!<unset>!';
+               }
+
+               $pconfig = DBA::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $key]);
+               if (DBA::isResult($pconfig)) {
+                       // manage array value
+                       $value = (preg_match("|^a:[0-9]+:{.*}$|s", $pconfig['v']) ? unserialize($pconfig['v']) : $pconfig['v']);
+
+                       $this->in_db[$uid][$cat][$key] = true;
+                       return $value;
+               } else {
+
+                       $this->in_db[$uid][$cat][$key] = false;
+                       return '!<unset>!';
+               }
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function set($uid, $cat, $key, $value)
+       {
+               if (!$this->isConnected()) {
+                       return false;
+               }
+
+               // We store our setting values in a string variable.
+               // So we have to do the conversion here so that the compare below works.
+               // The exception are array values.
+               $dbvalue = (!is_array($value) ? (string)$value : $value);
+
+               $stored = $this->get($uid, $cat, $key);
+
+               if (!isset($this->in_db[$uid])) {
+                       $this->in_db[$uid] = [];
+               }
+               if (!isset($this->in_db[$uid][$cat])) {
+                       $this->in_db[$uid][$cat] = [];
+               }
+               if (!isset($this->in_db[$uid][$cat][$key])) {
+                       $this->in_db[$uid][$cat][$key] = false;
+               }
+
+               if (($stored === $dbvalue) && $this->in_db[$uid][$cat][$key]) {
+                       return true;
+               }
+
+               // manage array value
+               $dbvalue = (is_array($value) ? serialize($value) : $dbvalue);
+
+               $result = DBA::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $key], true);
+
+               $this->in_db[$uid][$cat][$key] = $result;
+
+               return $result;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function delete($uid, $cat, $key)
+       {
+               if (!$this->isConnected()) {
+                       return false;
+               }
+
+               if (!empty($this->in_db[$uid][$cat][$key])) {
+                       unset($this->in_db[$uid][$cat][$key]);
+               }
+
+               $result = DBA::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $key]);
+
+               return $result;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function isLoaded($uid, $cat, $key)
+       {
+               if (!$this->isConnected()) {
+                       return false;
+               }
+
+               return (isset($this->in_db[$uid][$cat][$key])) && $this->in_db[$uid][$cat][$key];
+       }
+}
diff --git a/src/Core/Config/Adapter/PreloadConfigAdapter.php b/src/Core/Config/Adapter/PreloadConfigAdapter.php
new file mode 100644 (file)
index 0000000..fa691a1
--- /dev/null
@@ -0,0 +1,116 @@
+<?php
+
+namespace Friendica\Core\Config\Adapter;
+
+use Friendica\Database\DBA;
+
+/**
+ * Preload Configuration Adapter
+ *
+ * Minimizes the number of database queries to retrieve configuration values at the cost of memory.
+ *
+ * @author Hypolite Petovan <hypolite@mrpetovan.com>
+ */
+class PreloadConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAdapter
+{
+       private $config_loaded = false;
+
+       /**
+        * {@inheritdoc}
+        */
+       public function load($cat = 'config')
+       {
+               $return = [];
+
+               if (!$this->isConnected()) {
+                       return $return;
+               }
+
+               if ($this->config_loaded) {
+                       return $return;
+               }
+
+               $configs = DBA::select('config', ['cat', 'v', 'k']);
+               while ($config = DBA::fetch($configs)) {
+                       $return[$config['cat']][$config['k']] = $config['v'];
+               }
+               DBA::close($configs);
+
+               $this->config_loaded = true;
+
+               return $return;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function get($cat, $key)
+       {
+               if (!$this->isConnected()) {
+                       return '!<unset>!';
+               }
+
+               $config = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $key]);
+               if (DBA::isResult($config)) {
+                       // manage array value
+                       $value = (preg_match("|^a:[0-9]+:{.*}$|s", $config['v']) ? unserialize($config['v']) : $config['v']);
+
+                       return $value;
+               } else {
+
+                       return '!<unset>!';
+               }
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function set($cat, $key, $value)
+       {
+               if (!$this->isConnected()) {
+                       return false;
+               }
+
+               // We store our setting values as strings.
+               // So we have to do the conversion here so that the compare below works.
+               // The exception are array values.
+               $compare_value = !is_array($value) ? (string)$value : $value;
+
+               if ($this->get($cat, $key) === $compare_value) {
+                       return true;
+               }
+
+               // manage array value
+               $dbvalue = is_array($value) ? serialize($value) : $value;
+
+               $result = DBA::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $key], true);
+
+               return $result;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function delete($cat, $key)
+       {
+               if (!$this->isConnected()) {
+                       return false;
+               }
+
+               $result = DBA::delete('config', ['cat' => $cat, 'k' => $key]);
+
+               return $result;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function isLoaded($cat, $key)
+       {
+               if (!$this->isConnected()) {
+                       return false;
+               }
+
+               return $this->config_loaded;
+       }
+}
diff --git a/src/Core/Config/Adapter/PreloadPConfigAdapter.php b/src/Core/Config/Adapter/PreloadPConfigAdapter.php
new file mode 100644 (file)
index 0000000..e79a4a1
--- /dev/null
@@ -0,0 +1,138 @@
+<?php
+
+namespace Friendica\Core\Config\Adapter;
+
+use Friendica\Database\DBA;
+
+/**
+ * Preload User Configuration Adapter
+ *
+ * Minimizes the number of database queries to retrieve configuration values at the cost of memory.
+ *
+ * @author Hypolite Petovan <hypolite@mrpetovan.com>
+ */
+class PreloadPConfigAdapter extends AbstractDbaConfigAdapter implements IPConfigAdapter
+{
+       private $config_loaded = false;
+
+       /**
+        * @param int $uid The UID of the current user
+        */
+       public function __construct($uid = null)
+       {
+               parent::__construct();
+
+               if (isset($uid)) {
+                       $this->load($uid, 'config');
+               }
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function load($uid, $cat)
+       {
+               $return = [];
+
+               if ($this->config_loaded) {
+                       return $return;
+               }
+
+               if (empty($uid)) {
+                       return $return;
+               }
+
+               $pconfigs = DBA::select('pconfig', ['cat', 'v', 'k'], ['uid' => $uid]);
+               while ($pconfig = DBA::fetch($pconfigs)) {
+                       $return[$pconfig['cat']][$pconfig['k']] = $pconfig['v'];
+               }
+               DBA::close($pconfigs);
+
+               $this->config_loaded = true;
+
+               return $return;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function get($uid, $cat, $key)
+       {
+               if (!$this->isConnected()) {
+                       return '!<unset>!';
+               }
+
+               if (!$this->config_loaded) {
+                       $this->load($uid, $cat);
+               }
+
+               $config = DBA::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $key]);
+               if (DBA::isResult($config)) {
+                       // manage array value
+                       $value = (preg_match("|^a:[0-9]+:{.*}$|s", $config['v']) ? unserialize($config['v']) : $config['v']);
+
+                       return $value;
+               } else {
+                       return '!<unset>!';
+               }
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function set($uid, $cat, $key, $value)
+       {
+               if (!$this->isConnected()) {
+                       return false;
+               }
+
+               if (!$this->config_loaded) {
+                       $this->load($uid, $cat);
+               }
+               // We store our setting values as strings.
+               // So we have to do the conversion here so that the compare below works.
+               // The exception are array values.
+               $compare_value = !is_array($value) ? (string)$value : $value;
+
+               if ($this->get($uid, $cat, $key) === $compare_value) {
+                       return true;
+               }
+
+               // manage array value
+               $dbvalue = is_array($value) ? serialize($value) : $value;
+
+               $result = DBA::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $key], true);
+
+               return $result;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function delete($uid, $cat, $key)
+       {
+               if (!$this->isConnected()) {
+                       return false;
+               }
+
+               if (!$this->config_loaded) {
+                       $this->load($uid, $cat);
+               }
+
+               $result = DBA::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $key]);
+
+               return $result;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function isLoaded($uid, $cat, $key)
+       {
+               if (!$this->isConnected()) {
+                       return false;
+               }
+
+               return $this->config_loaded;
+       }
+}
diff --git a/src/Core/Config/Cache/ConfigCache.php b/src/Core/Config/Cache/ConfigCache.php
new file mode 100644 (file)
index 0000000..54da327
--- /dev/null
@@ -0,0 +1,206 @@
+<?php
+
+namespace Friendica\Core\Config\Cache;
+
+/**
+ * The Friendica config cache for the application
+ * Initial, all *.config.php files are loaded into this cache with the
+ * ConfigCacheLoader ( @see ConfigCacheLoader )
+ *
+ * Is used for further caching operations too (depending on the ConfigAdapter )
+ */
+class ConfigCache implements IConfigCache, IPConfigCache
+{
+       /**
+        * @var array
+        */
+       private $config;
+
+       /**
+        * @param array $config    A initial config array
+        */
+       public function __construct(array $config = [])
+       {
+               $this->load($config);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function load(array $config, $overwrite = false)
+       {
+               $categories = array_keys($config);
+
+               foreach ($categories as $category) {
+                       if (isset($config[$category]) && is_array($config[$category])) {
+                               $keys = array_keys($config[$category]);
+
+                               foreach ($keys as $key) {
+                                       if (isset($config[$category][$key])) {
+                                               if ($overwrite) {
+                                                       $this->set($category, $key, $config[$category][$key]);
+                                               } else {
+                                                       $this->setDefault($category, $key, $config[$category][$key]);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function get($cat, $key = null)
+       {
+               if (isset($this->config[$cat][$key])) {
+                       return $this->config[$cat][$key];
+               } elseif ($key == null && isset($this->config[$cat])) {
+                       return $this->config[$cat];
+               } else {
+                       return '!<unset>!';
+               }
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function has($cat, $key = null)
+       {
+               return (isset($this->config[$cat][$key]) && $this->config[$cat][$key] !== '!<unset>!') ||
+               ($key == null && isset($this->config[$cat]) && $this->config[$cat] !== '!<unset>!' && is_array($this->config[$cat]));
+       }
+
+       /**
+        * Sets a default value in the config cache. Ignores already existing keys.
+        *
+        * @param string $cat Config category
+        * @param string $k   Config key
+        * @param mixed  $v   Default value to set
+        */
+       private function setDefault($cat, $k, $v)
+       {
+               if (!isset($this->config[$cat][$k])) {
+                       $this->set($cat, $k, $v);
+               }
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function set($cat, $key, $value)
+       {
+               // Only arrays are serialized in database, so we have to unserialize sparingly
+               $value = is_string($value) && preg_match("|^a:[0-9]+:{.*}$|s", $value) ? unserialize($value) : $value;
+
+               if (!isset($this->config[$cat])) {
+                       $this->config[$cat] = [];
+               }
+
+               $this->config[$cat][$key] = $value;
+
+               return true;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function hasP($uid, $cat, $key = null)
+       {
+               return (isset($this->config[$uid][$cat][$key]) && $this->config[$uid][$cat][$key] !== '!<unset>!') ||
+                       ($key == null && isset($this->config[$uid][$cat]) && $this->config[$uid][$cat] !== '!<unset>!' && is_array($this->config[$uid][$cat]));
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function delete($cat, $key)
+       {
+               if (isset($this->config[$cat][$key])) {
+                       unset($this->config[$cat][$key]);
+                       if (count($this->config[$cat]) == 0) {
+                               unset($this->config[$cat]);
+                       }
+                       return true;
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function loadP($uid, array $config)
+       {
+               foreach ($config as $category => $values) {
+                       foreach ($values as $key => $value) {
+                               $this->setP($uid, $category, $key, $value);
+                       }
+               }
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function getP($uid, $cat, $key = null)
+       {
+               if (isset($this->config[$uid][$cat][$key])) {
+                       return $this->config[$uid][$cat][$key];
+               } elseif ($key == null && isset($this->config[$uid][$cat])) {
+                       return $this->config[$uid][$cat];
+               } else {
+                       return '!<unset>!';
+               }
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function setP($uid, $cat, $key, $value)
+       {
+               // Only arrays are serialized in database, so we have to unserialize sparingly
+               $value = is_string($value) && preg_match("|^a:[0-9]+:{.*}$|s", $value) ? unserialize($value) : $value;
+
+               if (!isset($this->config[$uid]) || !is_array($this->config[$uid])) {
+                       $this->config[$uid] = [];
+               }
+
+               if (!isset($this->config[$uid][$cat])) {
+                       $this->config[$uid][$cat] = [];
+               }
+
+               $this->config[$uid][$cat][$key] = $value;
+
+               return true;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function deleteP($uid, $cat, $key)
+       {
+               if (isset($this->config[$uid][$cat][$key])) {
+                       unset($this->config[$uid][$cat][$key]);
+                       if (count($this->config[$uid][$cat]) == 0) {
+                               unset($this->config[$uid][$cat]);
+                               if (count($this->config[$uid]) == 0) {
+                                       unset($this->config[$uid]);
+                               }
+                       }
+
+                       return true;
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * Returns the whole configuration
+        *
+        * @return array The configuration
+        */
+       public function getAll()
+       {
+               return $this->config;
+       }
+}
diff --git a/src/Core/Config/Cache/ConfigCacheLoader.php b/src/Core/Config/Cache/ConfigCacheLoader.php
new file mode 100644 (file)
index 0000000..b728d10
--- /dev/null
@@ -0,0 +1,200 @@
+<?php
+
+namespace Friendica\Core\Config\Cache;
+
+use Friendica\Core\Addon;
+
+/**
+ * The ConfigCacheLoader loads config-files and stores them in a ConfigCache ( @see ConfigCache )
+ *
+ * It is capable of loading the following config files:
+ * - *.config.php   (current)
+ * - *.ini.php      (deprecated)
+ * - *.htconfig.php (deprecated)
+ */
+class ConfigCacheLoader
+{
+       /**
+        * The Sub directory of the config-files
+        * @var string
+        */
+       const SUBDIRECTORY = 'config';
+
+       private $baseDir;
+       private $configDir;
+
+       public function __construct($baseDir)
+       {
+               $this->baseDir = $baseDir;
+               $this->configDir = $baseDir . DIRECTORY_SEPARATOR . self::SUBDIRECTORY;
+       }
+
+       /**
+        * Load the configuration files
+        *
+        * First loads the default value for all the configuration keys, then the legacy configuration files, then the
+        * expected local.config.php
+        */
+       public function loadConfigFiles(ConfigCache $config)
+       {
+               // Setting at least the basepath we know
+               $config->set('system', 'basepath', $this->baseDir);
+
+               $config->load($this->loadCoreConfig('defaults'));
+               $config->load($this->loadCoreConfig('settings'));
+
+               $config->load($this->loadLegacyConfig('htpreconfig'), true);
+               $config->load($this->loadLegacyConfig('htconfig'), true);
+
+               $config->load($this->loadCoreConfig('local'), true);
+       }
+
+       /**
+        * Tries to load the specified core-configuration and returns the config array.
+        *
+        * @param string $name The name of the configuration
+        *
+        * @return array The config array (empty if no config found)
+        *
+        * @throws \Exception if the configuration file isn't readable
+        */
+       public function loadCoreConfig($name)
+       {
+               if (file_exists($this->configDir . DIRECTORY_SEPARATOR . $name . '.config.php')) {
+                       return $this->loadConfigFile($this->configDir . DIRECTORY_SEPARATOR . $name . '.config.php');
+               } elseif (file_exists($this->configDir . DIRECTORY_SEPARATOR . $name . '.ini.php')) {
+                       return $this->loadINIConfigFile($this->configDir . DIRECTORY_SEPARATOR . $name . '.ini.php');
+               } else {
+                       return [];
+               }
+       }
+
+       /**
+        * Tries to load the specified addon-configuration and returns the config array.
+        *
+        * @param string $name The name of the configuration
+        *
+        * @return array The config array (empty if no config found)
+        *
+        * @throws \Exception if the configuration file isn't readable
+        */
+       public function loadAddonConfig($name)
+       {
+               $filepath = $this->baseDir . DIRECTORY_SEPARATOR . // /var/www/html/
+                       Addon::DIRECTORY       . DIRECTORY_SEPARATOR . // addon/
+                       $name                  . DIRECTORY_SEPARATOR . // openstreetmap/
+                       self::SUBDIRECTORY     . DIRECTORY_SEPARATOR . // config/
+                       $name . ".config.php";                         // openstreetmap.config.php
+
+               if (file_exists($filepath)) {
+                       return $this->loadConfigFile($filepath);
+               } else {
+                       return [];
+               }
+       }
+
+       /**
+        * Tries to load the legacy config files (.htconfig.php, .htpreconfig.php) and returns the config array.
+        *
+        * @param string $name The name of the config file
+        *
+        * @return array The configuration array (empty if no config found)
+        *
+        * @deprecated since version 2018.09
+        */
+       private function loadLegacyConfig($name)
+       {
+               $filePath = $this->baseDir  . DIRECTORY_SEPARATOR . '.' . $name . '.php';
+
+               if (file_exists($filePath)) {
+                       $a = new \stdClass();
+                       $a->config = [];
+                       include $filePath;
+
+                       if (isset($db_host)) {
+                               $a->config['database']['hostname'] = $db_host;
+                               unset($db_host);
+                       }
+                       if (isset($db_user)) {
+                               $a->config['database']['username'] = $db_user;
+                               unset($db_user);
+                       }
+                       if (isset($db_pass)) {
+                               $a->config['database']['password'] = $db_pass;
+                               unset($db_pass);
+                       }
+                       if (isset($db_data)) {
+                               $a->config['database']['database'] = $db_data;
+                               unset($db_data);
+                       }
+                       if (isset($a->config['system']['db_charset'])) {
+                               $a->config['database']['charset'] = $a->config['system']['charset'];
+                       }
+                       if (isset($pidfile)) {
+                               $a->config['system']['pidfile'] = $pidfile;
+                               unset($pidfile);
+                       }
+                       if (isset($default_timezone)) {
+                               $a->config['system']['default_timezone'] = $default_timezone;
+                               unset($default_timezone);
+                       }
+                       if (isset($lang)) {
+                               $a->config['system']['language'] = $lang;
+                               unset($lang);
+                       }
+
+                       return $a->config;
+               } else {
+                       return [];
+               }
+       }
+
+       /**
+        * Tries to load the specified legacy configuration file and returns the config array.
+        *
+        * @deprecated since version 2018.12
+        * @param string $filepath
+        *
+        * @return array The configuration array
+        * @throws \Exception
+        */
+       private function loadINIConfigFile($filepath)
+       {
+               $contents = include($filepath);
+
+               $config = parse_ini_string($contents, true, INI_SCANNER_TYPED);
+
+               if ($config === false) {
+                       throw new \Exception('Error parsing INI config file ' . $filepath);
+               }
+
+               return $config;
+       }
+
+       /**
+        * Tries to load the specified configuration file and returns the config array.
+        *
+        * The config format is PHP array and the template for configuration files is the following:
+        *
+        * <?php return [
+        *      'section' => [
+        *          'key' => 'value',
+        *      ],
+        * ];
+        *
+        * @param  string $filepath The filepath of the
+        * @return array The config array0
+        *
+        * @throws \Exception if the config cannot get loaded.
+        */
+       private function loadConfigFile($filepath)
+       {
+               $config = include($filepath);
+
+               if (!is_array($config)) {
+                       throw new \Exception('Error loading config file ' . $filepath);
+               }
+
+               return $config;
+       }
+}
diff --git a/src/Core/Config/Cache/IConfigCache.php b/src/Core/Config/Cache/IConfigCache.php
new file mode 100644 (file)
index 0000000..9d94852
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+
+namespace Friendica\Core\Config\Cache;
+
+/**
+ * The interface for a system-wide ConfigCache
+ */
+interface IConfigCache
+{
+       /**
+        * Tries to load the specified configuration array into the config array.
+        * Doesn't overwrite previously set values by default to prevent default config files to supersede DB Config.
+        *
+        * @param array $config
+        * @param bool  $overwrite Force value overwrite if the config key already exists
+        */
+       function load(array $config, $overwrite = false);
+
+       /**
+        * Gets a value from the config cache.
+        *
+        * @param string $cat     Config category
+        * @param string $key       Config key
+        *
+        * @return mixed Returns the value of the Config entry or '!<unset>!' if not set
+        */
+       function get($cat, $key = null);
+
+       /**
+        * Sets a value in the config cache. Accepts raw output from the config table
+        *
+        * @param string $cat   Config category
+        * @param string $key   Config key
+        * @param mixed  $value Value to set
+        *
+        * @return bool True, if the value is set
+        */
+       function set($cat, $key, $value);
+
+       /**
+        * Deletes a value from the config cache.
+        *
+        * @param string $cat  Config category
+        * @param string $key  Config key
+        *
+        * @return bool true, if deleted
+        */
+       function delete($cat, $key);
+
+       /**
+        * Checks if a value is set in the config cache.
+        *
+        * @param string $cat  Config category
+        * @param string $key  Config key
+        * @return bool
+        */
+       function has($cat, $key = null);
+
+       /**
+        * Returns the whole configuration cache
+        *
+        * @return array
+        */
+       function getAll();
+}
diff --git a/src/Core/Config/Cache/IPConfigCache.php b/src/Core/Config/Cache/IPConfigCache.php
new file mode 100644 (file)
index 0000000..4ac2148
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+
+namespace Friendica\Core\Config\Cache;
+
+/**
+ * The interface for a user-specific config cache
+ */
+interface IPConfigCache
+{
+       /**
+        * Tries to load the specified configuration array into the user specific config array.
+        * Doesn't overwrite previously set values by default to prevent default config files to supersede DB Config.
+        *
+        * @param int   $uid
+        * @param array $config
+        */
+       function loadP($uid, array $config);
+
+       /**
+        * Retrieves a value from the user config cache
+        *
+        * @param int    $uid     User Id
+        * @param string $cat     Config category
+        * @param string $key     Config key
+        *
+        * @return string The value of the config entry or '!<unset>!' if not set
+        */
+       function getP($uid, $cat, $key = null);
+
+       /**
+        * Sets a value in the user config cache
+        *
+        * Accepts raw output from the pconfig table
+        *
+        * @param int    $uid   User Id
+        * @param string $cat   Config category
+        * @param string $key   Config key
+        * @param mixed  $value Value to set
+        */
+       function setP($uid, $cat, $key, $value);
+
+       /**
+        * Deletes a value from the user config cache
+        *
+        * @param int    $uid User Id
+        * @param string $cat Config category
+        * @param string $key Config key
+        *
+        * @return bool true, if deleted
+        */
+       function deleteP($uid, $cat, $key);
+
+
+       /**
+        * Checks if a value is set in the user config cache.
+        *
+        * @param int    $uid  User Id
+        * @param string $cat  Config category
+        * @param string $key  Config key
+        * @return bool
+        */
+       function hasP($uid, $cat, $key = null);
+
+       /**
+        * Returns the whole configuration cache
+        *
+        * @return array
+        */
+       function getAll();
+}
diff --git a/src/Core/Config/ConfigCache.php b/src/Core/Config/ConfigCache.php
deleted file mode 100644 (file)
index b86ec38..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-<?php
-
-namespace Friendica\Core\Config;
-
-/**
- * The Friendica config cache for the application
- * Initial, all *.config.php files are loaded into this cache with the
- * ConfigCacheLoader ( @see ConfigCacheLoader )
- *
- * Is used for further caching operations too (depending on the ConfigAdapter )
- */
-class ConfigCache implements IConfigCache, IPConfigCache
-{
-       private $config;
-
-       /**
-        * @param array $config    A initial config array
-        */
-       public function __construct(array $config = [])
-       {
-               $this->loadConfigArray($config);
-       }
-
-       /**
-        * Tries to load the specified configuration array into the App->config array.
-        * Doesn't overwrite previously set values by default to prevent default config files to supersede DB Config.
-        *
-        * @param array $config
-        * @param bool  $overwrite Force value overwrite if the config key already exists
-        */
-       public function loadConfigArray(array $config, $overwrite = false)
-       {
-               foreach ($config as $category => $values) {
-                       foreach ($values as $key => $value) {
-                               if ($overwrite) {
-                                       $this->set($category, $key, $value);
-                               } else {
-                                       $this->setDefault($category, $key, $value);
-                               }
-                       }
-               }
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function get($cat, $key = null, $default = null)
-       {
-               $return = $default;
-
-               if ($cat === 'config') {
-                       if (isset($this->config[$key])) {
-                               $return = $this->config[$key];
-                       }
-               } else {
-                       if (isset($this->config[$cat][$key])) {
-                               $return = $this->config[$cat][$key];
-                       } elseif ($key == null && isset($this->config[$cat])) {
-                               $return = $this->config[$cat];
-                       }
-               }
-
-               return $return;
-       }
-
-       /**
-        * Sets a default value in the config cache. Ignores already existing keys.
-        *
-        * @param string $cat Config category
-        * @param string $k   Config key
-        * @param mixed  $v   Default value to set
-        */
-       private function setDefault($cat, $k, $v)
-       {
-               if (!isset($this->config[$cat][$k])) {
-                       $this->set($cat, $k, $v);
-               }
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function set($cat, $key, $value)
-       {
-               // Only arrays are serialized in database, so we have to unserialize sparingly
-               $value = is_string($value) && preg_match("|^a:[0-9]+:{.*}$|s", $value) ? unserialize($value) : $value;
-
-               if ($cat === 'config') {
-                       $this->config[$key] = $value;
-               } else {
-                       if (!isset($this->config[$cat])) {
-                               $this->config[$cat] = [];
-                       }
-
-                       $this->config[$cat][$key] = $value;
-               }
-
-               return true;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function delete($cat, $key)
-       {
-               if ($cat === 'config') {
-                       if (isset($this->config[$key])) {
-                               unset($this->config[$key]);
-                       }
-               } else {
-                       if (isset($this->config[$cat][$key])) {
-                               unset($this->config[$cat][$key]);
-                               if (count($this->config[$cat]) == 0) {
-                                       unset($this->config[$cat]);
-                               }
-                       }
-               }
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function getP($uid, $cat, $key = null, $default = null)
-       {
-               $return = $default;
-
-               if (isset($this->config[$uid][$cat][$key])) {
-                       $return = $this->config[$uid][$cat][$key];
-               } elseif ($key === null && isset($this->config[$uid][$cat])) {
-                       $return = $this->config[$uid][$cat];
-               }
-
-               return $return;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function setP($uid, $cat, $key, $value)
-       {
-               // Only arrays are serialized in database, so we have to unserialize sparingly
-               $value = is_string($value) && preg_match("|^a:[0-9]+:{.*}$|s", $value) ? unserialize($value) : $value;
-
-               if (!isset($this->config[$uid]) || !is_array($this->config[$uid])) {
-                       $this->config[$uid] = [];
-               }
-
-               if (!isset($this->config[$uid][$cat]) || !is_array($this->config[$uid][$cat])) {
-                       $this->config[$uid][$cat] = [];
-               }
-
-               if ($key === null) {
-                       $this->config[$uid][$cat] = $value;
-               } else {
-                       $this->config[$uid][$cat][$key] = $value;
-               }
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function deleteP($uid, $cat, $key)
-       {
-               if (isset($this->config[$uid][$cat][$key])) {
-                       unset($this->config[$uid][$cat][$key]);
-                       if (count($this->config[$uid][$cat]) == 0) {
-                               unset($this->config[$uid][$cat]);
-                               if (count($this->config[$uid]) == 0) {
-                                       unset($this->config[$uid]);
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Returns the whole configuration
-        *
-        * @return array The configuration
-        */
-       public function getAll()
-       {
-               return $this->config;
-       }
-}
diff --git a/src/Core/Config/ConfigCacheLoader.php b/src/Core/Config/ConfigCacheLoader.php
deleted file mode 100644 (file)
index 3a6a3c8..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-<?php
-
-namespace Friendica\Core\Config;
-
-use Friendica\Core\Addon;
-
-/**
- * The ConfigCacheLoader loads config-files and stores them in a ConfigCache ( @see ConfigCache )
- *
- * It is capable of loading the following config files:
- * - *.config.php   (current)
- * - *.ini.php      (deprecated)
- * - *.htconfig.php (deprecated)
- */
-class ConfigCacheLoader
-{
-       /**
-        * The Sub directory of the config-files
-        * @var string
-        */
-       const SUBDIRECTORY = 'config';
-
-       private $baseDir;
-       private $configDir;
-
-       public function __construct($baseDir)
-       {
-               $this->baseDir = $baseDir;
-               $this->configDir = $baseDir . DIRECTORY_SEPARATOR . self::SUBDIRECTORY;
-       }
-
-       /**
-        * Load the configuration files
-        *
-        * First loads the default value for all the configuration keys, then the legacy configuration files, then the
-        * expected local.config.php
-        */
-       public function loadConfigFiles(ConfigCache $config)
-       {
-               // Setting at least the basepath we know
-               $config->set('system', 'basepath', $this->baseDir);
-
-               $config->loadConfigArray($this->loadCoreConfig('defaults'));
-               $config->loadConfigArray($this->loadCoreConfig('settings'));
-
-               $config->loadConfigArray($this->loadLegacyConfig('htpreconfig'), true);
-               $config->loadConfigArray($this->loadLegacyConfig('htconfig'), true);
-
-               $config->loadConfigArray($this->loadCoreConfig('local'), true);
-       }
-
-       /**
-        * Tries to load the specified core-configuration and returns the config array.
-        *
-        * @param string $name The name of the configuration
-        *
-        * @return array The config array (empty if no config found)
-        *
-        * @throws \Exception if the configuration file isn't readable
-        */
-       public function loadCoreConfig($name)
-       {
-               if (file_exists($this->configDir . DIRECTORY_SEPARATOR . $name . '.config.php')) {
-                       return $this->loadConfigFile($this->configDir . DIRECTORY_SEPARATOR . $name . '.config.php');
-               } elseif (file_exists($this->configDir . DIRECTORY_SEPARATOR . $name . '.ini.php')) {
-                       return $this->loadINIConfigFile($this->configDir . DIRECTORY_SEPARATOR . $name . '.ini.php');
-               } else {
-                       return [];
-               }
-       }
-
-       /**
-        * Tries to load the specified addon-configuration and returns the config array.
-        *
-        * @param string $name The name of the configuration
-        *
-        * @return array The config array (empty if no config found)
-        *
-        * @throws \Exception if the configuration file isn't readable
-        */
-       public function loadAddonConfig($name)
-       {
-               $filepath = $this->baseDir . DIRECTORY_SEPARATOR . // /var/www/html/
-                       Addon::DIRECTORY       . DIRECTORY_SEPARATOR . // addon/
-                       $name                  . DIRECTORY_SEPARATOR . // openstreetmap/
-                       self::SUBDIRECTORY     . DIRECTORY_SEPARATOR . // config/
-                       $name . ".config.php";                         // openstreetmap.config.php
-
-               if (file_exists($filepath)) {
-                       return $this->loadConfigFile($filepath);
-               } else {
-                       return [];
-               }
-       }
-
-       /**
-        * Tries to load the legacy config files (.htconfig.php, .htpreconfig.php) and returns the config array.
-        *
-        * @param string $name The name of the config file
-        *
-        * @return array The configuration array (empty if no config found)
-        *
-        * @deprecated since version 2018.09
-        */
-       private function loadLegacyConfig($name)
-       {
-               $filePath = $this->baseDir  . DIRECTORY_SEPARATOR . '.' . $name . '.php';
-
-               if (file_exists($filePath)) {
-                       $a = new \stdClass();
-                       $a->config = [];
-                       include $filePath;
-
-                       if (isset($db_host)) {
-                               $a->config['database']['hostname'] = $db_host;
-                               unset($db_host);
-                       }
-                       if (isset($db_user)) {
-                               $a->config['database']['username'] = $db_user;
-                               unset($db_user);
-                       }
-                       if (isset($db_pass)) {
-                               $a->config['database']['password'] = $db_pass;
-                               unset($db_pass);
-                       }
-                       if (isset($db_data)) {
-                               $a->config['database']['database'] = $db_data;
-                               unset($db_data);
-                       }
-                       if (isset($a->config['system']['db_charset'])) {
-                               $a->config['database']['charset'] = $a->config['system']['charset'];
-                       }
-                       if (isset($pidfile)) {
-                               $a->config['system']['pidfile'] = $pidfile;
-                               unset($pidfile);
-                       }
-                       if (isset($default_timezone)) {
-                               $a->config['system']['default_timezone'] = $default_timezone;
-                               unset($default_timezone);
-                       }
-                       if (isset($lang)) {
-                               $a->config['system']['language'] = $lang;
-                               unset($lang);
-                       }
-
-                       return $a->config;
-               } else {
-                       return [];
-               }
-       }
-
-       /**
-        * Tries to load the specified legacy configuration file and returns the config array.
-        *
-        * @deprecated since version 2018.12
-        * @param string $filepath
-        *
-        * @return array The configuration array
-        * @throws \Exception
-        */
-       private function loadINIConfigFile($filepath)
-       {
-               $contents = include($filepath);
-
-               $config = parse_ini_string($contents, true, INI_SCANNER_TYPED);
-
-               if ($config === false) {
-                       throw new \Exception('Error parsing INI config file ' . $filepath);
-               }
-
-               return $config;
-       }
-
-       /**
-        * Tries to load the specified configuration file and returns the config array.
-        *
-        * The config format is PHP array and the template for configuration files is the following:
-        *
-        * <?php return [
-        *      'section' => [
-        *          'key' => 'value',
-        *      ],
-        * ];
-        *
-        * @param  string $filepath The filepath of the
-        * @return array The config array0
-        *
-        * @throws \Exception if the config cannot get loaded.
-        */
-       private function loadConfigFile($filepath)
-       {
-               $config = include($filepath);
-
-               if (!is_array($config)) {
-                       throw new \Exception('Error loading config file ' . $filepath);
-               }
-
-               return $config;
-       }
-}
diff --git a/src/Core/Config/Configuration.php b/src/Core/Config/Configuration.php
new file mode 100644 (file)
index 0000000..2ac0da0
--- /dev/null
@@ -0,0 +1,153 @@
+<?php
+
+namespace Friendica\Core\Config;
+
+/**
+ * This class is responsible for all system-wide configuration values in Friendica
+ * There are two types of storage
+ * - The Config-Files    (loaded into the FileCache @see Cache\IConfigCache )
+ * - The Config-DB-Table (per Config-DB-adapter @see Adapter\IConfigAdapter )
+ */
+class Configuration
+{
+       /**
+        * @var Cache\IConfigCache
+        */
+       private $configCache;
+
+       /**
+        * @var Adapter\IConfigAdapter
+        */
+       private $configAdapter;
+
+       /**
+        * @param Cache\IConfigCache     $configCache   The configuration cache (based on the config-files)
+        * @param Adapter\IConfigAdapter $configAdapter The configuration DB-backend
+        */
+       public function __construct(Cache\IConfigCache $configCache, Adapter\IConfigAdapter $configAdapter)
+       {
+               $this->configCache = $configCache;
+               $this->configAdapter = $configAdapter;
+
+               $this->load();
+       }
+
+       /**
+        * Returns the Config Cache
+        *
+        * @return Cache\IConfigCache
+        */
+       public function getCache()
+       {
+               return $this->configCache;
+       }
+
+       /**
+        * @brief Loads all configuration values of family into a cached storage.
+        *
+        * All configuration values of the system are stored in the cache ( @see IConfigCache )
+        *
+        * @param string $cat The category of the configuration value
+        *
+        * @return void
+        */
+       public function load($cat = 'config')
+       {
+               // If not connected, do nothing
+               if (!$this->configAdapter->isConnected()) {
+                       return;
+               }
+
+               // load the whole category out of the DB into the cache
+               $this->configCache->load($this->configAdapter->load($cat), true);
+       }
+
+       /**
+        * @brief Get a particular user's config variable given the category name
+        * ($cat) and a $key.
+        *
+        * Get a particular config value from the given category ($cat)
+        * and the $key from a cached storage either from the $this->configAdapter
+        * (@see IConfigAdapter ) or from the $this->configCache (@see IConfigCache ).
+        *
+        * @param string  $cat        The category of the configuration value
+        * @param string  $key           The configuration key to query
+        * @param mixed   $default_value optional, The value to return if key is not set (default: null)
+        * @param boolean $refresh       optional, If true the config is loaded from the db and not from the cache (default: false)
+        *
+        * @return mixed Stored value or null if it does not exist
+        */
+       public function get($cat, $key, $default_value = null, $refresh = false)
+       {
+               // if the value isn't loaded or refresh is needed, load it to the cache
+               if ($this->configAdapter->isConnected() &&
+                       (!$this->configAdapter->isLoaded($cat, $key) ||
+                       $refresh)) {
+                       $dbvalue = $this->configAdapter->get($cat, $key);
+
+                       if ($dbvalue !== '!<unset>!') {
+                               $this->configCache->set($cat, $key, $dbvalue);
+                               return $dbvalue;
+                       }
+               }
+
+               // use the config cache for return
+               if ($this->configCache->has($cat, $key)) {
+                       return $this->configCache->get($cat, $key);
+               } else {
+                       return $default_value;
+               }
+       }
+
+       /**
+        * @brief Sets a configuration value for system config
+        *
+        * Stores a config value ($value) in the category ($cat) under the key ($key)
+        *
+        * Note: Please do not store booleans - convert to 0/1 integer values!
+        *
+        * @param string $cat The category of the configuration value
+        * @param string $key    The configuration key to set
+        * @param mixed  $value  The value to store
+        *
+        * @return bool Operation success
+        */
+       public function set($cat, $key, $value)
+       {
+               // set the cache first
+               $cached = $this->configCache->set($cat, $key, $value);
+
+               // If there is no connected adapter, we're finished
+               if (!$this->configAdapter->isConnected()) {
+                       return $cached;
+               }
+
+               $stored = $this->configAdapter->set($cat, $key, $value);
+
+               return $cached && $stored;
+       }
+
+       /**
+        * @brief Deletes the given key from the system configuration.
+        *
+        * Removes the configured value from the stored cache in $this->configCache
+        * (@see ConfigCache ) and removes it from the database (@see IConfigAdapter ).
+        *
+        * @param string $cat The category of the configuration value
+        * @param string $key    The configuration key to delete
+        *
+        * @return bool
+        */
+       public function delete($cat, $key)
+       {
+               $cacheRemoved = $this->configCache->delete($cat, $key);
+
+               if (!$this->configAdapter->isConnected()) {
+                       return $cacheRemoved;
+               }
+
+               $storeRemoved = $this->configAdapter->delete($cat, $key);
+
+               return $cacheRemoved || $storeRemoved;
+       }
+}
diff --git a/src/Core/Config/IConfigAdapter.php b/src/Core/Config/IConfigAdapter.php
deleted file mode 100644 (file)
index 70e1414..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-namespace Friendica\Core\Config;
-
-/**
- *
- * @author Hypolite Petovan <hypolite@mrpetovan.com>
- */
-interface IConfigAdapter
-{
-       /**
-        * Loads all configuration values into a cached storage.
-        *
-        * @param string  $cat The category of the configuration values to load
-        *
-        * @return void
-        */
-       public function load($cat = "config");
-
-       /**
-        * Get a particular user's config variable given the category name
-        * ($family) and a key.
-        *
-        * @param string  $cat           The category of the configuration value
-        * @param string  $k             The configuration key to query
-        * @param mixed   $default_value optional, The value to return if key is not set (default: null)
-        * @param boolean $refresh       optional, If true the config is loaded from the db and not from the cache (default: false)
-        *
-        * @return mixed Stored value or null if it does not exist
-        */
-       public function get($cat, $k, $default_value = null, $refresh = false);
-
-       /**
-        * Stores a config value ($value) in the category ($family) under the key ($key)
-        * for the user_id $uid.
-        *
-        * Note: Please do not store booleans - convert to 0/1 integer values!
-        *
-        * @param string $cat   The category of the configuration value
-        * @param string $k     The configuration key to set
-        * @param mixed  $value The value to store
-        *
-        * @return bool Operation success
-        */
-       public function set($cat, $k, $value);
-
-       /**
-        * Removes the configured value from the stored cache
-        * and removes it from the database.
-        *
-        * @param string $cat The category of the configuration value
-        * @param string $k   The configuration key to delete
-        *
-        * @return mixed
-        */
-       public function delete($cat, $k);
-
-       /**
-        * Checks, if the current adapter is connected to the backend
-        *
-        * @return bool
-        */
-       public function isConnected();
-}
diff --git a/src/Core/Config/IConfigCache.php b/src/Core/Config/IConfigCache.php
deleted file mode 100644 (file)
index 898e3c0..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-namespace Friendica\Core\Config;
-
-/**
- * The interface for a system-wide ConfigCache
- */
-interface IConfigCache
-{
-       /**
-        * @param string $cat     Config category
-        * @param string $key       Config key
-        * @param mixed  $default Default value if it isn't set
-        *
-        * @return mixed Returns the value of the Config entry
-        */
-       function get($cat, $key = null, $default = null);
-
-       /**
-        * Sets a value in the config cache. Accepts raw output from the config table
-        *
-        * @param string $cat   Config category
-        * @param string $key   Config key
-        * @param mixed  $value Value to set
-        *
-        * @return bool True, if the value is set
-        */
-       function set($cat, $key, $value);
-
-       /**
-        * Deletes a value from the config cache
-        *
-        * @param string $cat  Config category
-        * @param string $key  Config key
-        */
-       function delete($cat, $key);
-
-       function getAll();
-}
diff --git a/src/Core/Config/IPConfigAdapter.php b/src/Core/Config/IPConfigAdapter.php
deleted file mode 100644 (file)
index e62fc9c..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
-
-namespace Friendica\Core\Config;
-
-/**
- *
- * @author benlo
- */
-interface IPConfigAdapter
-{
-       /**
-        * Loads all configuration values of a user's config family into a cached storage.
-        *
-        * @param string $uid The user_id
-        * @param string $cat The category of the configuration value
-        *
-        * @return void
-        */
-       public function load($uid, $cat);
-
-       /**
-        * Get a particular user's config variable given the category name
-        * ($family) and a key.
-        *
-        * @param string  $uid           The user_id
-        * @param string  $cat           The category of the configuration value
-        * @param string  $k             The configuration key to query
-        * @param mixed   $default_value optional, The value to return if key is not set (default: null)
-        * @param boolean $refresh       optional, If true the config is loaded from the db and not from the cache (default: false)
-        *
-        * @return mixed Stored value or null if it does not exist
-        */
-       public function get($uid, $cat, $k, $default_value = null, $refresh = false);
-
-       /**
-        * Stores a config value ($value) in the category ($family) under the key ($key)
-        * for the user_id $uid.
-        *
-        * @note Please do not store booleans - convert to 0/1 integer values!
-        *
-        * @param string $uid   The user_id
-        * @param string $cat   The category of the configuration value
-        * @param string $k     The configuration key to set
-        * @param string $value The value to store
-        *
-        * @return bool Operation success
-        */
-       public function set($uid, $cat, $k, $value);
-
-       /**
-        * Removes the configured value from the stored cache
-        * and removes it from the database.
-        *
-        * @param string $uid The user_id
-        * @param string $cat The category of the configuration value
-        * @param string $k   The configuration key to delete
-        *
-        * @return mixed
-        */
-       public function delete($uid, $cat, $k);
-}
diff --git a/src/Core/Config/IPConfigCache.php b/src/Core/Config/IPConfigCache.php
deleted file mode 100644 (file)
index 6a57daf..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-namespace Friendica\Core\Config;
-
-/**
- * The interface for a user-specific config cache
- */
-interface IPConfigCache
-{
-       /**
-        * Retrieves a value from the user config cache
-        *
-        * @param int    $uid     User Id
-        * @param string $cat     Config category
-        * @param string $key     Config key
-        * @param mixed  $default Default value if key isn't set
-        *
-        * @return string The value of the config entry
-        */
-       function getP($uid, $cat, $key = null, $default = null);
-
-       /**
-        * Sets a value in the user config cache
-        *
-        * Accepts raw output from the pconfig table
-        *
-        * @param int    $uid   User Id
-        * @param string $cat   Config category
-        * @param string $key   Config key
-        * @param mixed  $value Value to set
-        */
-       function setP($uid, $cat, $key, $value);
-
-       /**
-        * Deletes a value from the user config cache
-        *
-        * @param int    $uid User Id
-        * @param string $cat Config category
-        * @param string $key Config key
-        */
-       function deleteP($uid, $cat, $key);
-
-       function getAll();
-}
diff --git a/src/Core/Config/JITConfigAdapter.php b/src/Core/Config/JITConfigAdapter.php
deleted file mode 100644 (file)
index ecd88bb..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-<?php
-namespace Friendica\Core\Config;
-
-use Friendica\Database\DBA;
-
-/**
- * JustInTime Configuration Adapter
- *
- * Default Config Adapter. Provides the best performance for pages loading few configuration variables.
- *
- * @author Hypolite Petovan <hypolite@mrpetovan.com>
- */
-class JITConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAdapter
-{
-       private $cache;
-       private $in_db;
-
-       /**
-        * @var IConfigCache The config cache of this driver
-        */
-       private $configCache;
-
-       /**
-        * @param IConfigCache $configCache The config cache of this driver
-        */
-       public function __construct(IConfigCache $configCache)
-       {
-               $this->configCache = $configCache;
-               $this->connected = DBA::connected();
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function load($cat = "config")
-       {
-               if (!$this->isConnected()) {
-                       return;
-               }
-
-               // We don't preload "system" anymore.
-               // This reduces the number of database reads a lot.
-               if ($cat === 'system') {
-                       return;
-               }
-
-               $configs = DBA::select('config', ['v', 'k'], ['cat' => $cat]);
-               while ($config = DBA::fetch($configs)) {
-                       $k = $config['k'];
-
-                       $this->configCache->set($cat, $k, $config['v']);
-
-                       if ($cat !== 'config') {
-                               $this->cache[$cat][$k] = $config['v'];
-                               $this->in_db[$cat][$k] = true;
-                       }
-               }
-               DBA::close($configs);
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function get($cat, $k, $default_value = null, $refresh = false)
-       {
-               if (!$this->isConnected()) {
-                       return $default_value;
-               }
-
-               if (!$refresh) {
-                       // Do we have the cached value? Then return it
-                       if (isset($this->cache[$cat][$k])) {
-                               if ($this->cache[$cat][$k] === '!<unset>!') {
-                                       return $default_value;
-                               } else {
-                                       return $this->cache[$cat][$k];
-                               }
-                       }
-               }
-
-               $config = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $k]);
-               if (DBA::isResult($config)) {
-                       // manage array value
-                       $value = (preg_match("|^a:[0-9]+:{.*}$|s", $config['v']) ? unserialize($config['v']) : $config['v']);
-
-                       // Assign the value from the database to the cache
-                       $this->cache[$cat][$k] = $value;
-                       $this->in_db[$cat][$k] = true;
-                       return $value;
-               } elseif ($this->configCache->get($cat, $k) !== null) {
-                       // Assign the value (mostly) from config/local.config.php file to the cache
-                       $this->cache[$cat][$k] = $this->configCache->get($cat, $k);
-                       $this->in_db[$cat][$k] = false;
-
-                       return $this->configCache->get($cat, $k);
-               } elseif ($this->configCache->get('config', $k) !== null) {
-                       // Assign the value (mostly) from config/local.config.php file to the cache
-                       $this->cache[$k] = $this->configCache->get('config', $k);
-                       $this->in_db[$k] = false;
-
-                       return $this->configCache->get('config', $k);
-               }
-
-               $this->cache[$cat][$k] = '!<unset>!';
-               $this->in_db[$cat][$k] = false;
-
-               return $default_value;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function set($cat, $k, $value)
-       {
-               if (!$this->isConnected()) {
-                       return false;
-               }
-
-               // We store our setting values in a string variable.
-               // So we have to do the conversion here so that the compare below works.
-               // The exception are array values.
-               $dbvalue = (!is_array($value) ? (string)$value : $value);
-
-               $stored = $this->get($cat, $k, null, true);
-
-               if (!isset($this->in_db[$cat])) {
-                       $this->in_db[$cat] = [];
-               }
-               if (!isset($this->in_db[$cat][$k])) {
-                       $this->in_db[$cat] = false;
-               }
-
-               if (($stored === $dbvalue) && $this->in_db[$cat][$k]) {
-                       return true;
-               }
-
-               $this->configCache->set($cat, $k, $value);
-
-               // Assign the just added value to the cache
-               $this->cache[$cat][$k] = $dbvalue;
-
-               // manage array value
-               $dbvalue = (is_array($value) ? serialize($value) : $dbvalue);
-
-               $result = DBA::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $k], true);
-
-               if ($result) {
-                       $this->in_db[$cat][$k] = true;
-               }
-
-               return $result;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function delete($cat, $k)
-       {
-               if (!$this->isConnected()) {
-                       return false;
-               }
-
-               if (isset($this->cache[$cat][$k])) {
-                       unset($this->cache[$cat][$k]);
-                       unset($this->in_db[$cat][$k]);
-               }
-
-               $result = DBA::delete('config', ['cat' => $cat, 'k' => $k]);
-
-               return $result;
-       }
-}
diff --git a/src/Core/Config/JITPConfigAdapter.php b/src/Core/Config/JITPConfigAdapter.php
deleted file mode 100644 (file)
index b1a1560..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-<?php
-namespace Friendica\Core\Config;
-
-use Friendica\Database\DBA;
-
-/**
- * JustInTime User Configuration Adapter
- *
- * Default PConfig Adapter. Provides the best performance for pages loading few configuration variables.
- *
- * @author Hypolite Petovan <hypolite@mrpetovan.com>
- */
-class JITPConfigAdapter implements IPConfigAdapter
-{
-       private $in_db;
-
-       /**
-        * The config cache of this adapter
-        * @var IPConfigCache
-        */
-       private $configCache;
-
-       /**
-        * @param IPConfigCache $configCache The config cache of this adapter
-        */
-       public function __construct(IPConfigCache $configCache)
-       {
-               $this->configCache = $configCache;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function load($uid, $cat)
-       {
-               $pconfigs = DBA::select('pconfig', ['v', 'k'], ['cat' => $cat, 'uid' => $uid]);
-               if (DBA::isResult($pconfigs)) {
-                       while ($pconfig = DBA::fetch($pconfigs)) {
-                               $k = $pconfig['k'];
-
-                               $this->configCache->setP($uid, $cat, $k, $pconfig['v']);
-
-                               $this->in_db[$uid][$cat][$k] = true;
-                       }
-               } else if ($cat != 'config') {
-                       // Negative caching
-                       $this->configCache->setP($uid, $cat, null, "!<unset>!");
-               }
-               DBA::close($pconfigs);
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function get($uid, $cat, $k, $default_value = null, $refresh = false)
-       {
-               if (!$refresh) {
-                       // Looking if the whole family isn't set
-                       if ($this->configCache->getP($uid, $cat) !== null) {
-                               if ($this->configCache->getP($uid, $cat) === '!<unset>!') {
-                                       return $default_value;
-                               }
-                       }
-
-                       if ($this->configCache->getP($uid, $cat, $k) !== null) {
-                               if ($this->configCache->getP($uid, $cat, $k) === '!<unset>!') {
-                                       return $default_value;
-                               }
-                               return $this->configCache->getP($uid, $cat, $k);
-                       }
-               }
-
-               $pconfig = DBA::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
-               if (DBA::isResult($pconfig)) {
-                       $val = (preg_match("|^a:[0-9]+:{.*}$|s", $pconfig['v']) ? unserialize($pconfig['v']) : $pconfig['v']);
-
-                       $this->configCache->setP($uid, $cat, $k, $val);
-
-                       $this->in_db[$uid][$cat][$k] = true;
-
-                       return $val;
-               } else {
-                       $this->configCache->setP($uid, $cat, $k, '!<unset>!');
-
-                       $this->in_db[$uid][$cat][$k] = false;
-
-                       return $default_value;
-               }
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function set($uid, $cat, $k, $value)
-       {
-               // We store our setting values in a string variable.
-               // So we have to do the conversion here so that the compare below works.
-               // The exception are array values.
-               $dbvalue = (!is_array($value) ? (string)$value : $value);
-
-               $stored = $this->get($uid, $cat, $k, null, true);
-
-               if (($stored === $dbvalue) && $this->in_db[$uid][$cat][$k]) {
-                       return true;
-               }
-
-               $this->configCache->setP($uid, $cat, $k, $value);
-
-               // manage array value
-               $dbvalue = (is_array($value) ? serialize($value) : $dbvalue);
-
-               $result = DBA::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $k], true);
-
-               if ($result) {
-                       $this->in_db[$uid][$cat][$k] = true;
-               }
-
-               return $result;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function delete($uid, $cat, $k)
-       {
-               $this->configCache->deleteP($uid, $cat, $k);
-
-               if (!empty($this->in_db[$uid][$cat][$k])) {
-                       unset($this->in_db[$uid][$cat][$k]);
-               }
-
-               $result = DBA::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
-
-               return $result;
-       }
-}
diff --git a/src/Core/Config/PConfiguration.php b/src/Core/Config/PConfiguration.php
new file mode 100644 (file)
index 0000000..99b1aa1
--- /dev/null
@@ -0,0 +1,149 @@
+<?php
+
+namespace Friendica\Core\Config;
+
+/**
+ * This class is responsible for the user-specific configuration values in Friendica
+ * The values are set through the Config-DB-Table (per Config-DB-adapter @see Adapter\IPConfigAdapter )
+ *
+ * The configuration cache (@see Cache\IPConfigCache ) is used for temporary caching of database calls. This will
+ * increase the performance.
+ */
+class PConfiguration
+{
+       /**
+        * @var Cache\IPConfigCache
+        */
+       private $configCache;
+
+       /**
+        * @var Adapter\IPConfigAdapter
+        */
+       private $configAdapter;
+
+       /**
+        * @param Cache\IPConfigCache     $configCache   The configuration cache
+        * @param Adapter\IPConfigAdapter $configAdapter The configuration DB-backend
+        */
+       public function __construct(Cache\IPConfigCache $configCache, Adapter\IPConfigAdapter $configAdapter)
+       {
+               $this->configCache = $configCache;
+               $this->configAdapter = $configAdapter;
+       }
+
+       /**
+        * @brief Loads all configuration values of a user's config family into a cached storage.
+        *
+        * All configuration values of the given user are stored with the $uid in
+        * the cache ( @see IPConfigCache )
+        *
+        * @param string $uid The user_id
+        * @param string $cat The category of the configuration value
+        *
+        * @return void
+        */
+       public function load($uid, $cat = 'config')
+       {
+               // If not connected, do nothing
+               if (!$this->configAdapter->isConnected()) {
+                       return;
+               }
+
+               // load the whole category out of the DB into the cache
+               $this->configCache->loadP($uid, $this->configAdapter->load($uid, $cat));
+       }
+
+       /**
+        * @brief Get a particular user's config variable given the category name
+        * ($cat) and a key.
+        *
+        * Get a particular user's config value from the given category ($cat)
+        * and the $key with the $uid from a cached storage either from the $this->configAdapter
+        * (@see IConfigAdapter ) or from the $this->configCache (@see IConfigCache ).
+        *
+        * @param string  $uid           The user_id
+        * @param string  $cat           The category of the configuration value
+        * @param string  $key           The configuration key to query
+        * @param mixed   $default_value optional, The value to return if key is not set (default: null)
+        * @param boolean $refresh       optional, If true the config is loaded from the db and not from the cache (default: false)
+        *
+        * @return mixed Stored value or null if it does not exist
+        */
+       public function get($uid, $cat, $key, $default_value = null, $refresh = false)
+       {
+               // if the value isn't loaded or refresh is needed, load it to the cache
+               if ($this->configAdapter->isConnected() &&
+                       (!$this->configAdapter->isLoaded($uid, $cat, $key) ||
+                               $refresh)) {
+                       $dbValue = $this->configAdapter->get($uid, $cat, $key);
+
+                       if ($dbValue !== '!<unset>!') {
+                               $this->configCache->setP($uid, $cat, $key, $dbValue);
+                               return $dbValue;
+                       }
+               }
+
+               // use the config cache for return
+               if ($this->configCache->hasP($uid, $cat, $key)) {
+                       return $this->configCache->getP($uid, $cat, $key);
+               } else {
+                       return $default_value;
+               }
+       }
+
+       /**
+        * @brief Sets a configuration value for a user
+        *
+        * Stores a config value ($value) in the category ($family) under the key ($key)
+        * for the user_id $uid.
+        *
+        * @note  Please do not store booleans - convert to 0/1 integer values!
+        *
+        * @param string $uid    The user_id
+        * @param string $cat    The category of the configuration value
+        * @param string $key    The configuration key to set
+        * @param mixed  $value  The value to store
+        *
+        * @return bool Operation success
+        */
+       public function set($uid, $cat, $key, $value)
+       {
+               // set the cache first
+               $cached = $this->configCache->setP($uid, $cat, $key, $value);
+
+               // If there is no connected adapter, we're finished
+               if (!$this->configAdapter->isConnected()) {
+                       return $cached;
+               }
+
+               $stored = $this->configAdapter->set($uid, $cat, $key, $value);
+
+               return $cached && $stored;
+       }
+
+       /**
+        * @brief Deletes the given key from the users's configuration.
+        *
+        * Removes the configured value from the stored cache in $this->configCache
+        * (@see ConfigCache ) and removes it from the database (@see IConfigAdapter )
+        * with the given $uid.
+        *
+        * @param string $uid The user_id
+        * @param string $cat The category of the configuration value
+        * @param string $key The configuration key to delete
+        *
+        * @return bool
+        */
+       public function delete($uid, $cat, $key)
+       {
+               $cacheRemoved = $this->configCache->deleteP($uid, $cat, $key);
+
+               if (!$this->configAdapter->isConnected()) {
+                       return $cacheRemoved;
+               }
+
+               $storeRemoved = $this->configAdapter->delete($uid, $cat, $key);
+
+               return $cacheRemoved || $storeRemoved;
+       }
+}
diff --git a/src/Core/Config/PreloadConfigAdapter.php b/src/Core/Config/PreloadConfigAdapter.php
deleted file mode 100644 (file)
index 96331e7..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-<?php
-
-namespace Friendica\Core\Config;
-
-use Exception;
-use Friendica\Database\DBA;
-
-/**
- * Preload Configuration Adapter
- *
- * Minimizes the number of database queries to retrieve configuration values at the cost of memory.
- *
- * @author Hypolite Petovan <hypolite@mrpetovan.com>
- */
-class PreloadConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAdapter
-{
-       private $config_loaded = false;
-
-       /**
-        * @var IConfigCache The config cache of this driver
-        */
-       private $configCache;
-
-       /**
-        * @param IConfigCache $configCache The config cache of this driver
-        */
-       public function __construct(IConfigCache $configCache)
-       {
-               $this->configCache = $configCache;
-               $this->connected = DBA::connected();
-               $this->load();
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function load($family = 'config')
-       {
-               if (!$this->isConnected()) {
-                       return;
-               }
-
-               if ($this->config_loaded) {
-                       return;
-               }
-
-               $configs = DBA::select('config', ['cat', 'v', 'k']);
-               while ($config = DBA::fetch($configs)) {
-                       $this->configCache->set($config['cat'], $config['k'], $config['v']);
-               }
-               DBA::close($configs);
-
-               $this->config_loaded = true;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function get($cat, $k, $default_value = null, $refresh = false)
-       {
-               if (!$this->isConnected()) {
-                       return $default_value;
-               }
-
-               if ($refresh) {
-                       $config = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $k]);
-                       if (DBA::isResult($config)) {
-                               $this->configCache->set($cat, $k, $config['v']);
-                       }
-               }
-
-               $return = $this->configCache->get($cat, $k, $default_value);
-
-               return $return;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function set($cat, $k, $value)
-       {
-               if (!$this->isConnected()) {
-                       return false;
-               }
-
-               // We store our setting values as strings.
-               // So we have to do the conversion here so that the compare below works.
-               // The exception are array values.
-               $compare_value = !is_array($value) ? (string)$value : $value;
-
-               if ($this->configCache->get($cat, $k) === $compare_value) {
-                       return true;
-               }
-
-               $this->configCache->set($cat, $k, $value);
-
-               // manage array value
-               $dbvalue = is_array($value) ? serialize($value) : $value;
-
-               $result = DBA::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $k], true);
-               if (!$result) {
-                       throw new Exception('Unable to store config value in [' . $cat . '][' . $k . ']');
-               }
-
-               return true;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function delete($cat, $k)
-       {
-               if (!$this->isConnected()) {
-                       return false;
-               }
-
-               $this->configCache->delete($cat, $k);
-
-               $result = DBA::delete('config', ['cat' => $cat, 'k' => $k]);
-
-               return $result;
-       }
-}
diff --git a/src/Core/Config/PreloadPConfigAdapter.php b/src/Core/Config/PreloadPConfigAdapter.php
deleted file mode 100644 (file)
index af97815..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-<?php
-
-namespace Friendica\Core\Config;
-
-use Exception;
-use Friendica\Database\DBA;
-
-/**
- * Preload User Configuration Adapter
- *
- * Minimizes the number of database queries to retrieve configuration values at the cost of memory.
- *
- * @author Hypolite Petovan <hypolite@mrpetovan.com>
- */
-class PreloadPConfigAdapter implements IPConfigAdapter
-{
-       private $config_loaded = false;
-
-       /**
-        * The config cache of this adapter
-        * @var IPConfigCache
-        */
-       private $configCache;
-
-       /**
-        * @param IPConfigCache $configCache The config cache of this adapter
-        * @param int           $uid    The UID of the current user
-        */
-       public function __construct(IPConfigCache $configCache, $uid = null)
-       {
-               $this->configCache = $configCache;
-               if (isset($uid)) {
-                       $this->load($uid, 'config');
-               }
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function load($uid, $family)
-       {
-               if ($this->config_loaded) {
-                       return;
-               }
-
-               if (empty($uid)) {
-                       return;
-               }
-
-               $pconfigs = DBA::select('pconfig', ['cat', 'v', 'k'], ['uid' => $uid]);
-               while ($pconfig = DBA::fetch($pconfigs)) {
-                       $this->configCache->setP($uid, $pconfig['cat'], $pconfig['k'], $pconfig['v']);
-               }
-               DBA::close($pconfigs);
-
-               $this->config_loaded = true;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function get($uid, $cat, $k, $default_value = null, $refresh = false)
-       {
-               if (!$this->config_loaded) {
-                       $this->load($uid, $cat);
-               }
-
-               if ($refresh) {
-                       $config = DBA::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
-                       if (DBA::isResult($config)) {
-                               $this->configCache->setP($uid, $cat, $k, $config['v']);
-                       } else {
-                               $this->configCache->deleteP($uid, $cat, $k);
-                       }
-               }
-
-               return $this->configCache->getP($uid, $cat, $k, $default_value);;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function set($uid, $cat, $k, $value)
-       {
-               if (!$this->config_loaded) {
-                       $this->load($uid, $cat);
-               }
-               // We store our setting values as strings.
-               // So we have to do the conversion here so that the compare below works.
-               // The exception are array values.
-               $compare_value = !is_array($value) ? (string)$value : $value;
-
-               if ($this->configCache->getP($uid, $cat, $k) === $compare_value) {
-                       return true;
-               }
-
-               $this->configCache->setP($uid, $cat, $k, $value);
-
-               // manage array value
-               $dbvalue = is_array($value) ? serialize($value) : $value;
-
-               $result = DBA::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $k], true);
-               if (!$result) {
-                       throw new Exception('Unable to store config value in [' . $uid . '][' . $cat . '][' . $k . ']');
-               }
-
-               return true;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function delete($uid, $cat, $k)
-       {
-               if (!$this->config_loaded) {
-                       $this->load($uid, $cat);
-               }
-
-               $this->configCache->deleteP($uid, $cat, $k);
-
-               $result = DBA::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
-
-               return $result;
-       }
-}
index 7f2585e63a3f359bfee056fbfa2f79a40bd59f21..682d109712fb5fbfee1e551455ac2222714379cb 100644 (file)
@@ -100,10 +100,10 @@ HELP;
                                }
                        }
 
-                       $db_host = $a->getConfig()->get('database', 'hostname');
-                       $db_user = $a->getConfig()->get('database', 'username');
-                       $db_pass = $a->getConfig()->get('database', 'password');
-                       $db_data = $a->getConfig()->get('database', 'database');
+                       $db_host = $a->getConfigCache()->get('database', 'hostname');
+                       $db_user = $a->getConfigCache()->get('database', 'username');
+                       $db_pass = $a->getConfigCache()->get('database', 'password');
+                       $db_data = $a->getConfigCache()->get('database', 'database');
                } else {
                        // Creating config file
                        $this->out("Creating config file...\n");
@@ -146,7 +146,7 @@ HELP;
 
                $installer->resetChecks();
 
-               if (!$installer->checkDB($a->getConfig(), $db_host, $db_user, $db_pass, $db_data)) {
+               if (!$installer->checkDB($a->getConfigCache(), $a->getProfiler(), $db_host, $db_user, $db_pass, $db_data)) {
                        $errorMessage = $this->extractErrors($installer->getChecks());
                        throw new RuntimeException($errorMessage);
                }
index b1c3df54e024fc59738c259c9cddf0b54327292b..cf5c09fc0a4281bf5e6fe925d768f65e396a8f6c 100644 (file)
@@ -124,9 +124,9 @@ HELP;
                        $cat = $this->getArgument(0);
                        Core\Config::load($cat);
 
-                       if ($a->getConfig()->get($cat) !== null) {
+                       if ($a->getConfigCache()->get($cat) !== null) {
                                $this->out("[{$cat}]");
-                               $catVal = $a->getConfig()->get($cat);
+                               $catVal = $a->getConfigCache()->get($cat);
                                foreach ($catVal as $key => $value) {
                                        if (is_array($value)) {
                                                foreach ($value as $k => $v) {
@@ -148,7 +148,7 @@ HELP;
                                $this->out('Warning: The JIT (Just In Time) Config adapter doesn\'t support loading the entire configuration, showing file config only');
                        }
 
-                       $config = $a->getConfig()->getAll();
+                       $config = $a->getConfigCache()->getAll();
                        foreach ($config as $cat => $section) {
                                if (is_array($section)) {
                                        foreach ($section as $key => $value) {
index 32ba6ded35186878bea79e9bf8cac456c8444172..8d07051e8393861679c1b82b2ad8f848709fab3c 100644 (file)
@@ -43,7 +43,7 @@ HELP;
                        throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
                }
 
-               $php_path = BaseObject::getApp()->getConfig()->get('config', 'php_path', 'php');
+               $php_path = BaseObject::getApp()->getConfigCache()->get('config', 'php_path', 'php');
 
                if ($this->getOption('v')) {
                        $this->out('Directory: src');
index fdeb940a2577a1ee7c595fd21dcffd4619f5de22..ed4721014191dac11316bb8eb8bf685849b58de0 100644 (file)
@@ -6,11 +6,12 @@ namespace Friendica\Core;
 
 use DOMDocument;
 use Exception;
-use Friendica\Core\Config\ConfigCache;
+use Friendica\Core\Config\Cache\IConfigCache;
 use Friendica\Database\DBA;
 use Friendica\Database\DBStructure;
 use Friendica\Object\Image;
 use Friendica\Util\Network;
+use Friendica\Util\Profiler;
 use Friendica\Util\Strings;
 
 /**
@@ -590,7 +591,8 @@ class Installer
        /**
         * Checking the Database connection and if it is available for the current installation
         *
-        * @param ConfigCache $configCache The configuration cache
+        * @param IConfigCache $configCache The configuration cache
+        * @param Profiler    $profiler    The profiler of this app
         * @param string $dbhost           Hostname/IP of the Friendica Database
         * @param string $dbuser           Username of the Database connection credentials
         * @param string $dbpass           Password of the Database connection credentials
@@ -599,9 +601,9 @@ class Installer
         * @return bool true if the check was successful, otherwise false
         * @throws Exception
         */
-       public function checkDB(ConfigCache $configCache, $dbhost, $dbuser, $dbpass, $dbdata)
+       public function checkDB(IConfigCache $configCache, Profiler $profiler, $dbhost, $dbuser, $dbpass, $dbdata)
        {
-               if (!DBA::connect($configCache, $dbhost, $dbuser, $dbpass, $dbdata)) {
+               if (!DBA::connect($configCache, $profiler, $dbhost, $dbuser, $dbpass, $dbdata)) {
                        $this->addCheck(L10n::t('Could not connect to database.'), false, true, '');
 
                        return false;
index 6b8112796f557f00dea156a9c22fef3993097584..3cb22e1e478aeef78dc2e2467af3fe35523c4771 100644 (file)
@@ -5,8 +5,6 @@
 namespace Friendica\Core;
 
 use Friendica\BaseObject;
-use Friendica\Factory\LoggerFactory;
-use Friendica\Network\HTTPException\InternalServerErrorException;
 use Psr\Log\LoggerInterface;
 use Psr\Log\LogLevel;
 
@@ -67,73 +65,22 @@ class Logger extends BaseObject
 
        /**
         * Sets the default logging handler for Friendica.
-        * @todo Can be combined with other handlers too if necessary, could be configurable.
         *
         * @param LoggerInterface $logger The Logger instance of this Application
-        *
-        * @throws InternalServerErrorException if the logger factory is incompatible to this logger
         */
-       public static function setLogger($logger)
+       public static function init(LoggerInterface $logger)
        {
-               $debugging = Config::get('system', 'debugging');
-               $logfile = Config::get('system', 'logfile');
-               $loglevel = Config::get('system', 'loglevel');
-
-               if (!$debugging || !$logfile) {
-                       return;
-               }
-
-               $loglevel = self::mapLegacyConfigDebugLevel((string)$loglevel);
-
-               LoggerFactory::addStreamHandler($logger, $logfile, $loglevel);
-
                self::$logger = $logger;
-
-               $logfile = Config::get('system', 'dlogfile');
-
-               if (!$logfile) {
-                       return;
-               }
-
-               $developIp = Config::get('system', 'dlogip');
-
-               self::$devLogger = LoggerFactory::createDev('develop', $developIp);
-               LoggerFactory::addStreamHandler(self::$devLogger, $logfile, LogLevel::DEBUG);
        }
 
        /**
-        * Mapping a legacy level to the PSR-3 compliant levels
-        * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel
+        * Sets the default dev-logging handler for Friendica.
         *
-        * @param string $level the level to be mapped
-        *
-        * @return string the PSR-3 compliant level
+        * @param LoggerInterface $logger The Logger instance of this Application
         */
-       private static function mapLegacyConfigDebugLevel($level)
+       public static function setDevLogger(LoggerInterface $logger)
        {
-               switch ($level) {
-                       // legacy WARNING
-                       case "0":
-                               return LogLevel::ERROR;
-                       // legacy INFO
-                       case "1":
-                               return LogLevel::WARNING;
-                       // legacy TRACE
-                       case "2":
-                               return LogLevel::NOTICE;
-                       // legacy DEBUG
-                       case "3":
-                               return LogLevel::INFO;
-                       // legacy DATA
-                       case "4":
-                               return LogLevel::DEBUG;
-                       // legacy ALL
-                       case "5":
-                               return LogLevel::DEBUG;
-                       // default if nothing set
-                       default:
-                               return $level;
-               }
+               self::$devLogger = $logger;
        }
 
        /**
@@ -155,7 +102,7 @@ class Logger extends BaseObject
 
                $stamp1 = microtime(true);
                self::$logger->emergency($message, $context);
-               self::getApp()->saveTimestamp($stamp1, 'file');
+               self::getApp()->GetProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
        }
 
        /**
@@ -179,7 +126,7 @@ class Logger extends BaseObject
 
                $stamp1 = microtime(true);
                self::$logger->alert($message, $context);
-               self::getApp()->saveTimestamp($stamp1, 'file');
+               self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
        }
 
        /**
@@ -202,7 +149,7 @@ class Logger extends BaseObject
 
                $stamp1 = microtime(true);
                self::$logger->critical($message, $context);
-               self::getApp()->saveTimestamp($stamp1, 'file');
+               self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
        }
 
        /**
@@ -225,7 +172,7 @@ class Logger extends BaseObject
 
                $stamp1 = microtime(true);
                self::$logger->error($message, $context);
-               self::getApp()->saveTimestamp($stamp1, 'file');
+               self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
        }
 
        /**
@@ -249,7 +196,7 @@ class Logger extends BaseObject
 
                $stamp1 = microtime(true);
                self::$logger->warning($message, $context);
-               self::getApp()->saveTimestamp($stamp1, 'file');
+               self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
        }
 
        /**
@@ -270,7 +217,7 @@ class Logger extends BaseObject
 
                $stamp1 = microtime(true);
                self::$logger->notice($message, $context);
-               self::getApp()->saveTimestamp($stamp1, 'file');
+               self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
        }
 
        /**
@@ -293,7 +240,7 @@ class Logger extends BaseObject
 
                $stamp1 = microtime(true);
                self::$logger->info($message, $context);
-               self::getApp()->saveTimestamp($stamp1, 'file');
+               self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
        }
 
        /**
@@ -314,28 +261,28 @@ class Logger extends BaseObject
 
                $stamp1 = microtime(true);
                self::$logger->debug($message, $context);
-               self::getApp()->saveTimestamp($stamp1, 'file');
+               self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
        }
 
-    /**
-     * @brief Logs the given message at the given log level
-     *
-     * @param string $msg
-     * @param string $level
+           /**
+        * @brief Logs the given message at the given log level
+        *
+        * @param string $msg
+        * @param string $level
         *
         * @throws \Exception
         * @deprecated since 2019.03 Use Logger::debug() Logger::info() , ... instead
-     */
-    public static function log($msg, $level = LogLevel::INFO)
-    {
+        */
+       public static function log($msg, $level = LogLevel::INFO)
+       {
                if (!isset(self::$logger)) {
                        return;
                }
 
-        $stamp1 = microtime(true);
+               $stamp1 = microtime(true);
                self::$logger->log($level, $msg);
-        self::getApp()->saveTimestamp($stamp1, "file");
-    }
+               self::getApp()->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
+       }
 
        /**
         * @brief An alternative logger for development.
@@ -347,14 +294,14 @@ class Logger extends BaseObject
         * @param string $level
         * @throws \Exception
         */
-    public static function devLog($msg, $level = LogLevel::DEBUG)
-    {
+       public static function devLog($msg, $level = LogLevel::DEBUG)
+       {
                if (!isset(self::$logger)) {
                        return;
                }
 
-        $stamp1 = microtime(true);
-        self::$devLogger->log($level, $msg);
-        self::getApp()->saveTimestamp($stamp1, "file");
-    }
+               $stamp1 = microtime(true);
+               self::$devLogger->log($level, $msg);
+               self::getApp()->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
+       }
 }
index df024f0f3426dfa84abc665789066a1c6427316a..f62b59f4765342e2b5b77fc5d35b9a09b6c9b1e2 100644 (file)
@@ -18,123 +18,78 @@ namespace Friendica\Core;
 class PConfig
 {
        /**
-        * @var Config\IPConfigAdapter
+        * @var Config\PConfiguration
         */
-       private static $adapter;
-
-       /**
-        * @var Config\IPConfigCache
-        */
-       private static $cache;
+       private static $config;
 
        /**
         * Initialize the config with only the cache
         *
-        * @param Config\IPConfigCache $cache  The configuration cache
-        */
-       public static function init(Config\IPConfigCache $cache)
-       {
-               self::$cache  = $cache;
-       }
-
-       /**
-        * Add the adapter for DB-backend
-        *
-        * @param Config\IPConfigAdapter $adapter
+        * @param Config\PConfiguration $config The configuration cache
         */
-       public static function setAdapter(Config\IPConfigAdapter $adapter)
+       public static function init(Config\PConfiguration $config)
        {
-               self::$adapter = $adapter;
+               self::$config = $config;
        }
 
        /**
         * @brief Loads all configuration values of a user's config family into a cached storage.
         *
-        * All configuration values of the given user are stored with the $uid in
-        * the cache ( @see IPConfigCache )
-        *
-        * @param string $uid    The user_id
-        * @param string $family The category of the configuration value
+        * @param string $uid The user_id
+        * @param string $cat The category of the configuration value
         *
         * @return void
         */
-       public static function load($uid, $family)
+       public static function load($uid, $cat)
        {
-               if (!isset(self::$adapter)) {
-                       return;
-               }
-
-               self::$adapter->load($uid, $family);
+               self::$config->load($uid, $cat);
        }
 
        /**
         * @brief Get a particular user's config variable given the category name
-        * ($family) and a key.
-        *
-        * Get a particular user's config value from the given category ($family)
-        * and the $key with the $uid from a cached storage either from the self::$adapter
-        * (@see IConfigAdapter ) or from the static::$cache (@see IConfigCache ).
+        * ($cat) and a key.
         *
         * @param string  $uid           The user_id
-        * @param string  $family        The category of the configuration value
+        * @param string  $cat           The category of the configuration value
         * @param string  $key           The configuration key to query
         * @param mixed   $default_value optional, The value to return if key is not set (default: null)
         * @param boolean $refresh       optional, If true the config is loaded from the db and not from the cache (default: false)
         *
         * @return mixed Stored value or null if it does not exist
         */
-       public static function get($uid, $family, $key, $default_value = null, $refresh = false)
+       public static function get($uid, $cat, $key, $default_value = null, $refresh = false)
        {
-               if (!isset(self::$adapter)) {
-                       return self::$cache->getP($uid, $family, $key, $default_value);
-               }
-
-               return self::$adapter->get($uid, $family, $key, $default_value, $refresh);
+               return self::$config->get($uid, $cat, $key, $default_value, $refresh);
        }
 
        /**
         * @brief Sets a configuration value for a user
         *
-        * Stores a config value ($value) in the category ($family) under the key ($key)
-        * for the user_id $uid.
-        *
         * @note  Please do not store booleans - convert to 0/1 integer values!
         *
         * @param string $uid    The user_id
-        * @param string $family The category of the configuration value
+        * @param string $cat    The category of the configuration value
         * @param string $key    The configuration key to set
         * @param mixed  $value  The value to store
         *
         * @return bool Operation success
         */
-       public static function set($uid, $family, $key, $value)
+       public static function set($uid, $cat, $key, $value)
        {
-               if (!isset(self::$adapter)) {
-                       return self::$cache->setP($uid, $family, $key, $value);
-               }
-
-               return self::$adapter->set($uid, $family, $key, $value);
+               return self::$config->set($uid, $cat, $key, $value);
        }
 
        /**
         * @brief Deletes the given key from the users's configuration.
         *
-        * Removes the configured value from the stored cache in self::$config
-        * (@see ConfigCache ) and removes it from the database (@see IConfigAdapter )
-        * with the given $uid.
-        *
-        * @param string $uid    The user_id
-        * @param string $family The category of the configuration value
-        * @param string $key    The configuration key to delete
+        * @param string $uid The user_id
+        * @param string $cat The category of the configuration value
+        * @param string $key The configuration key to delete
         *
-        * @return mixed
+        * @return bool
         */
-       public static function delete($uid, $family, $key)
+       public static function delete($uid, $cat, $key)
        {
-               if (!isset(self::$adapter)) {
-                       return self::$cache->deleteP($uid, $family, $key);
-               }
-
-               return self::$adapter->delete($uid, $family, $key);
+               return self::$config->delete($uid, $cat, $key);
        }
 }
index 67bc5e3babc515a6377d9b013a6e20d018d349b5..8844f26881c35183e84874ccfd5431881415a00e 100644 (file)
@@ -74,7 +74,7 @@ class Renderer extends BaseObject
             exit();
         }
 
-        $a->saveTimestamp($stamp1, "rendering");
+               $a->getProfiler()->saveTimestamp($stamp1, "rendering", System::callstack());
 
         return $output;
     }
@@ -101,7 +101,7 @@ class Renderer extends BaseObject
             exit();
         }
 
-        $a->saveTimestamp($stamp1, "file");
+        $a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
 
         return $template;
     }
index 62dfaa51f3072f45ce8d3bc56e871b2f0f4e3d5a..5479f8f46f8e2deeb097d1dd0c98d9401da0cccb 100644 (file)
@@ -51,7 +51,7 @@ class Theme
                $a = \get_app();
                $stamp1 = microtime(true);
                $theme_file = file_get_contents("view/theme/$theme/theme.php");
-               $a->saveTimestamp($stamp1, "file");
+               $a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
 
                $result = preg_match("|/\*.*\*/|msU", $theme_file, $matches);
 
index 75d4e48740ef60867b179a3da2ac12d97b5c5525..dff60e9fa5571187a09b913c2dedb7064669be6d 100644 (file)
@@ -380,20 +380,7 @@ class Worker
 
                // We use the callstack here to analyze the performance of executed worker entries.
                // For this reason the variables have to be initialized.
-               if (Config::get("system", "profiler")) {
-                       $a->performance["start"] = microtime(true);
-                       $a->performance["database"] = 0;
-                       $a->performance["database_write"] = 0;
-                       $a->performance["cache"] = 0;
-                       $a->performance["cache_write"] = 0;
-                       $a->performance["network"] = 0;
-                       $a->performance["file"] = 0;
-                       $a->performance["rendering"] = 0;
-                       $a->performance["parser"] = 0;
-                       $a->performance["marktime"] = 0;
-                       $a->performance["markstart"] = microtime(true);
-                       $a->callstack = [];
-               }
+               $a->getProfiler()->reset();
 
                // For better logging create a new process id for every worker call
                // But preserve the old one for the worker
@@ -452,76 +439,7 @@ class Worker
 
                Logger::log("Process ".$mypid." - Prio ".$queue["priority"]." - ID ".$queue["id"].": ".$funcname." - done in ".number_format($duration, 4)." seconds. Process PID: ".$new_process_id);
 
-               // Write down the performance values into the log
-               if (Config::get("system", "profiler")) {
-                       $duration = microtime(true)-$a->performance["start"];
-
-                       $o = '';
-                       if (Config::get("rendertime", "callstack")) {
-                               if (isset($a->callstack["database"])) {
-                                       $o .= "\nDatabase Read:\n";
-                                       foreach ($a->callstack["database"] as $func => $time) {
-                                               $time = round($time, 3);
-                                               if ($time > 0) {
-                                                       $o .= $func.": ".$time."\n";
-                                               }
-                                       }
-                               }
-                               if (isset($a->callstack["database_write"])) {
-                                       $o .= "\nDatabase Write:\n";
-                                       foreach ($a->callstack["database_write"] as $func => $time) {
-                                               $time = round($time, 3);
-                                               if ($time > 0) {
-                                                       $o .= $func.": ".$time."\n";
-                                               }
-                                       }
-                               }
-                               if (isset($a->callstack["dache"])) {
-                                       $o .= "\nCache Read:\n";
-                                       foreach ($a->callstack["dache"] as $func => $time) {
-                                               $time = round($time, 3);
-                                               if ($time > 0) {
-                                                       $o .= $func.": ".$time."\n";
-                                               }
-                                       }
-                               }
-                               if (isset($a->callstack["dache_write"])) {
-                                       $o .= "\nCache Write:\n";
-                                       foreach ($a->callstack["dache_write"] as $func => $time) {
-                                               $time = round($time, 3);
-                                               if ($time > 0) {
-                                                       $o .= $func.": ".$time."\n";
-                                               }
-                                       }
-                               }
-                               if (isset($a->callstack["network"])) {
-                                       $o .= "\nNetwork:\n";
-                                       foreach ($a->callstack["network"] as $func => $time) {
-                                               $time = round($time, 3);
-                                               if ($time > 0) {
-                                                       $o .= $func.": ".$time."\n";
-                                               }
-                                       }
-                               }
-                       }
-
-                       Logger::log(
-                               "ID ".$queue["id"].": ".$funcname.": ".sprintf(
-                                       "DB: %s/%s, Cache: %s/%s, Net: %s, I/O: %s, Other: %s, Total: %s".$o,
-                                       number_format($a->performance["database"] - $a->performance["database_write"], 2),
-                                       number_format($a->performance["database_write"], 2),
-                                       number_format($a->performance["cache"], 2),
-                                       number_format($a->performance["cache_write"], 2),
-                                       number_format($a->performance["network"], 2),
-                                       number_format($a->performance["file"], 2),
-                                       number_format($duration - ($a->performance["database"]
-                                               + $a->performance["cache"] + $a->performance["cache_write"]
-                                               + $a->performance["network"] + $a->performance["file"]), 2),
-                                       number_format($duration, 2)
-                               ),
-                               Logger::DEBUG
-                       );
-               }
+               $a->getProfiler()->saveLog("ID " . $queue["id"] . ": " . $funcname);
 
                $cooldown = Config::get("system", "worker_cooldown", 0);
 
index d2a739e9313aa07b9be4aaf948bab6398c1930e2..1c17d9aca52d38f7a59ea91e9a9cf2ccfef85c10 100644 (file)
@@ -2,10 +2,11 @@
 
 namespace Friendica\Database;
 
-use Friendica\Core\Config\IConfigCache;
+use Friendica\Core\Config\Cache\IConfigCache;
 use Friendica\Core\Logger;
 use Friendica\Core\System;
 use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Profiler;
 use mysqli;
 use mysqli_result;
 use mysqli_stmt;
@@ -35,6 +36,10 @@ class DBA
         * @var IConfigCache
         */
        private static $configCache;
+       /**
+        * @var Profiler
+        */
+       private static $profiler;
        private static $server_info = '';
        private static $connection;
        private static $driver;
@@ -50,7 +55,7 @@ class DBA
        private static $db_name = '';
        private static $db_charset = '';
 
-       public static function connect($configCache, $serveraddr, $user, $pass, $db, $charset = null)
+       public static function connect(IConfigCache $configCache, Profiler $profiler, $serveraddr, $user, $pass, $db, $charset = null)
        {
                if (!is_null(self::$connection) && self::connected()) {
                        return true;
@@ -58,6 +63,7 @@ class DBA
 
                // We are storing these values for being able to perform a reconnect
                self::$configCache = $configCache;
+               self::$profiler = $profiler;
                self::$db_serveraddr = $serveraddr;
                self::$db_user = $user;
                self::$db_pass = $pass;
@@ -158,7 +164,7 @@ class DBA
        public static function reconnect() {
                self::disconnect();
 
-               $ret = self::connect(self::$configCache, self::$db_serveraddr, self::$db_user, self::$db_pass, self::$db_name, self::$db_charset);
+               $ret = self::connect(self::$configCache, self::$profiler, self::$db_serveraddr, self::$db_user, self::$db_pass, self::$db_name, self::$db_charset);
                return $ret;
        }
 
@@ -392,7 +398,6 @@ class DBA
         * @throws \Exception
         */
        public static function p($sql) {
-               $a = \get_app();
 
                $stamp1 = microtime(true);
 
@@ -582,7 +587,7 @@ class DBA
                        self::$errorno = $errorno;
                }
 
-               $a->saveTimestamp($stamp1, 'database');
+               self::$profiler->saveTimestamp($stamp1, 'database', System::callstack());
 
                if (self::$configCache->get('system', 'db_log')) {
                        $stamp2 = microtime(true);
@@ -611,7 +616,6 @@ class DBA
         * @throws \Exception
         */
        public static function e($sql) {
-               $a = \get_app();
 
                $stamp = microtime(true);
 
@@ -654,7 +658,7 @@ class DBA
                        self::$errorno = $errorno;
                }
 
-               $a->saveTimestamp($stamp, "database_write");
+               self::$profiler->saveTimestamp($stamp, "database_write", System::callstack());
 
                return $retval;
        }
@@ -777,7 +781,6 @@ class DBA
         * @return array current row
         */
        public static function fetch($stmt) {
-               $a = \get_app();
 
                $stamp1 = microtime(true);
 
@@ -824,7 +827,7 @@ class DBA
                                }
                }
 
-               $a->saveTimestamp($stamp1, 'database');
+               self::$profiler->saveTimestamp($stamp1, 'database', System::callstack());
 
                return $columns;
        }
@@ -1534,7 +1537,6 @@ class DBA
         * @return boolean was the close successful?
         */
        public static function close($stmt) {
-               $a = \get_app();
 
                $stamp1 = microtime(true);
 
@@ -1562,7 +1564,7 @@ class DBA
                                break;
                }
 
-               $a->saveTimestamp($stamp1, 'database');
+               self::$profiler->saveTimestamp($stamp1, 'database', System::callstack());
 
                return $ret;
        }
index 269daea8b8d5514d6a19497a912dc43d54c50506..6a30cf0e0577d269b0468948ade177669d3826e3 100644 (file)
@@ -2,51 +2,66 @@
 
 namespace Friendica\Factory;
 
+use Friendica\Core;
 use Friendica\Core\Config;
+use Friendica\Core\Config\Adapter;
+use Friendica\Core\Config\Cache;
 
 class ConfigFactory
 {
        /**
-        * @param Config\ConfigCacheLoader $loader The Config Cache loader (INI/config/.htconfig)
+        * @param Cache\ConfigCacheLoader $loader The Config Cache loader (INI/config/.htconfig)
         *
-        * @return Config\ConfigCache
+        * @return Cache\ConfigCache
         */
-       public static function createCache(Config\ConfigCacheLoader $loader)
+       public static function createCache(Cache\ConfigCacheLoader $loader)
        {
-               $configCache = new Config\ConfigCache();
+               $configCache = new Cache\ConfigCache();
                $loader->loadConfigFiles($configCache);
 
                return $configCache;
        }
 
        /**
-        * @param string              $type   The adapter type
-        * @param Config\IConfigCache $config The config cache of this adapter
+        * @param Cache\ConfigCache $configCache The config cache of this adapter
         *
-        * @return Config\IConfigAdapter
+        * @return Config\Configuration
         */
-       public static function createConfig($type, Config\IConfigCache $config)
+       public static function createConfig(Cache\ConfigCache $configCache)
        {
-               if ($type == 'preload') {
-                       return new Config\PreloadConfigAdapter($config);
+               if ($configCache->get('system', 'config_adapter') === 'preload') {
+                       $configAdapter = new Adapter\PreloadConfigAdapter();
                } else {
-                       return new Config\JITConfigAdapter($config);
+                       $configAdapter = new Adapter\JITConfigAdapter();
                }
+
+               $configuration = new Config\Configuration($configCache, $configAdapter);
+
+               // Set the config in the static container for legacy usage
+               Core\Config::init($configuration);
+
+               return $configuration;
        }
 
        /**
-        * @param string               $type   The adapter type
-        * @param Config\IPConfigCache $config The config cache of this adapter
-        * @param int                  $uid    The UID of the current user
+        * @param Cache\ConfigCache  $configCache The config cache of this adapter
+        * @param int                $uid         The UID of the current user
         *
-        * @return Config\IPConfigAdapter
+        * @return Config\PConfiguration
         */
-       public static function createPConfig($type, Config\IPConfigCache $config, $uid = null)
+       public static function createPConfig(Cache\ConfigCache $configCache, $uid = null)
        {
-               if ($type == 'preload') {
-                       return new Config\PreloadPConfigAdapter($config, $uid);
+               if ($configCache->get('system', 'config_adapter') === 'preload') {
+                       $configAdapter = new Adapter\PreloadPConfigAdapter($uid);
                } else {
-                       return new Config\JITPConfigAdapter($config);
+                       $configAdapter = new Adapter\JITPConfigAdapter();
                }
+
+               $configuration = new Config\PConfiguration($configCache, $configAdapter);
+
+               // Set the config in the static container for legacy usage
+               Core\PConfig::init($configuration);
+
+               return $configuration;
        }
 }
diff --git a/src/Factory/DBFactory.php b/src/Factory/DBFactory.php
new file mode 100644 (file)
index 0000000..c1a7965
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+
+namespace Friendica\Factory;
+
+use Friendica\Core\Config\Cache;
+use Friendica\Database;
+use Friendica\Util\Profiler;
+
+class DBFactory
+{
+       /**
+        * Initialize the DBA connection
+        *
+        * @param Cache\IConfigCache $configCache The configuration cache
+        * @param Profiler          $profiler    The profiler
+        * @param array             $server      The $_SERVER variables
+        *
+        * @throws \Exception if connection went bad
+        */
+       public static function init(Cache\IConfigCache $configCache, Profiler $profiler, array $server)
+       {
+               if (Database\DBA::connected()) {
+                       return;
+               }
+
+               $db_host = $configCache->get('database', 'hostname');
+               $db_user = $configCache->get('database', 'username');
+               $db_pass = $configCache->get('database', 'password');
+               $db_data = $configCache->get('database', 'database');
+               $charset = $configCache->get('database', 'charset');
+
+               // Use environment variables for mysql if they are set beforehand
+               if (!empty($server['MYSQL_HOST'])
+                       && !empty($server['MYSQL_USERNAME'] || !empty($server['MYSQL_USER']))
+                       && $server['MYSQL_PASSWORD'] !== false
+                       && !empty($server['MYSQL_DATABASE']))
+               {
+                       $db_host = $server['MYSQL_HOST'];
+                       if (!empty($server['MYSQL_PORT'])) {
+                               $db_host .= ':' . $server['MYSQL_PORT'];
+                       }
+                       if (!empty($server['MYSQL_USERNAME'])) {
+                               $db_user = $server['MYSQL_USERNAME'];
+                       } else {
+                               $db_user = $server['MYSQL_USER'];
+                       }
+                       $db_pass = (string) $server['MYSQL_PASSWORD'];
+                       $db_data = $server['MYSQL_DATABASE'];
+               }
+
+               if (Database\DBA::connect($configCache, $profiler, $db_host, $db_user, $db_pass, $db_data, $charset)) {
+                       // Loads DB_UPDATE_VERSION constant
+                       Database\DBStructure::definition($configCache->get('system', 'basepath'), false);
+               }
+
+               unset($db_host, $db_user, $db_pass, $db_data, $charset);
+       }
+}
diff --git a/src/Factory/DependencyFactory.php b/src/Factory/DependencyFactory.php
new file mode 100644 (file)
index 0000000..acbf4bf
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+
+namespace Friendica\Factory;
+
+use Friendica\App;
+use Friendica\Core\Config\Cache;
+use Friendica\Factory;
+use Friendica\Util\BasePath;
+
+class DependencyFactory
+{
+       /**
+        * Setting all default-dependencies of a friendica execution
+        *
+        * @param string $channel   The channel of this execution
+        * @param string $directory The base directory
+        * @param bool   $isBackend True, if it's a backend execution, otherwise false (Default true)
+        *
+        * @return App The application
+        *
+        * @throws \Exception
+        */
+       public static function setUp($channel, $directory, $isBackend = true)
+       {
+               $basedir = BasePath::create($directory, $_SERVER);
+               $configLoader = new Cache\ConfigCacheLoader($basedir);
+               $configCache = Factory\ConfigFactory::createCache($configLoader);
+               $profiler = Factory\ProfilerFactory::create($configCache);
+               Factory\DBFactory::init($configCache, $profiler, $_SERVER);
+               $config = Factory\ConfigFactory::createConfig($configCache);
+               // needed to call PConfig::init()
+               Factory\ConfigFactory::createPConfig($configCache);
+               $logger = Factory\LoggerFactory::create($channel, $config);
+
+               return new App($config, $logger, $profiler, $isBackend);
+       }
+}
index 751a6357da84d4d3c00358196846979e949bfafb..77a09637c46d9dc3dffc23330f543de9ffe31e23 100644 (file)
@@ -2,10 +2,12 @@
 
 namespace Friendica\Factory;
 
-use Friendica\Core\Config\ConfigCache;
+use Friendica\Core\Config\Configuration;
+use Friendica\Core\Logger;
 use Friendica\Network\HTTPException\InternalServerErrorException;
 use Friendica\Util\Logger\FriendicaDevelopHandler;
 use Friendica\Util\Logger\FriendicaIntrospectionProcessor;
+use Friendica\Util\Profiler;
 use Monolog;
 use Psr\Log\LoggerInterface;
 use Psr\Log\LogLevel;
@@ -20,29 +22,32 @@ class LoggerFactory
        /**
         * Creates a new PSR-3 compliant logger instances
         *
-        * @param string      $channel The channel of the logger instance
-        * @param ConfigCache $config  The config
+        * @param string        $channel The channel of the logger instance
+        * @param Configuration $config  The config
         *
         * @return LoggerInterface The PSR-3 compliant logger instance
         */
-       public static function create($channel, ConfigCache $config = null)
+       public static function create($channel, Configuration $config)
        {
                $logger = new Monolog\Logger($channel);
                $logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
                $logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
                $logger->pushProcessor(new Monolog\Processor\UidProcessor());
-               $logger->pushProcessor(new FriendicaIntrospectionProcessor(LogLevel::DEBUG, ['Friendica\\Core\\Logger']));
+               $logger->pushProcessor(new FriendicaIntrospectionProcessor(LogLevel::DEBUG, [Logger::class, Profiler::class]));
 
-               if (isset($config)) {
-                       $debugging = $config->get('system', 'debugging');
-                       $stream = $config->get('system', 'logfile');
-                       $level = $config->get('system', 'loglevel');
+               $debugging = $config->get('system', 'debugging');
+               $stream    = $config->get('system', 'logfile');
+               $level     = $config->get('system', 'loglevel');
 
-                       if ($debugging) {
-                               static::addStreamHandler($logger, $stream, $level);
-                       }
+               if ($debugging) {
+                       $loglevel = self::mapLegacyConfigDebugLevel((string)$level);
+                       static::addStreamHandler($logger, $stream, $loglevel);
+               } else {
+                       static::addVoidHandler($logger);
                }
 
+               Logger::init($logger);
+
                return $logger;
        }
 
@@ -54,25 +59,71 @@ class LoggerFactory
         *
         * It should never get filled during normal usage of Friendica
         *
-        * @param string $channel      The channel of the logger instance
-        * @param string $developerIp  The IP of the developer who wants to use the logger
+        * @param string        $channel The channel of the logger instance
+        * @param Configuration $config  The config
         *
         * @return LoggerInterface The PSR-3 compliant logger instance
         */
-       public static function createDev($channel, $developerIp)
+       public static function createDev($channel, Configuration $config)
        {
+               $debugging   = $config->get('system', 'debugging');
+               $stream      = $config->get('system', 'dlogfile');
+               $developerIp = $config->get('system', 'dlogip');
+
+               if (!isset($developerIp) || !$debugging) {
+                       return null;
+               }
+
                $logger = new Monolog\Logger($channel);
                $logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
                $logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
                $logger->pushProcessor(new Monolog\Processor\UidProcessor());
                $logger->pushProcessor(new FriendicaIntrospectionProcessor(LogLevel::DEBUG, ['Friendica\\Core\\Logger']));
 
-
                $logger->pushHandler(new FriendicaDevelopHandler($developerIp));
 
+               static::addStreamHandler($logger, $stream, LogLevel::DEBUG);
+
+               Logger::setDevLogger($logger);
+
                return $logger;
        }
 
+       /**
+        * Mapping a legacy level to the PSR-3 compliant levels
+        * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel
+        *
+        * @param string $level the level to be mapped
+        *
+        * @return string the PSR-3 compliant level
+        */
+       private static function mapLegacyConfigDebugLevel($level)
+       {
+               switch ($level) {
+                       // legacy WARNING
+                       case "0":
+                               return LogLevel::ERROR;
+                       // legacy INFO
+                       case "1":
+                               return LogLevel::WARNING;
+                       // legacy TRACE
+                       case "2":
+                               return LogLevel::NOTICE;
+                       // legacy DEBUG
+                       case "3":
+                               return LogLevel::INFO;
+                       // legacy DATA
+                       case "4":
+                               return LogLevel::DEBUG;
+                       // legacy ALL
+                       case "5":
+                               return LogLevel::DEBUG;
+                       // default if nothing set
+                       default:
+                               return $level;
+               }
+       }
+
        /**
         * Adding a handler to a given logger instance
         *
@@ -105,31 +156,10 @@ class LoggerFactory
                }
        }
 
-       /**
-        * This method enables the test mode of a given logger
-        *
-        * @param LoggerInterface $logger The logger
-        *
-        * @return Monolog\Handler\TestHandler the Handling for tests
-        *
-        * @throws InternalServerErrorException if the logger is incompatible to the logger factory
-        */
-       public static function enableTest($logger)
+       public static function addVoidHandler($logger)
        {
                if ($logger instanceof Monolog\Logger) {
-                       // disable every handler so far
                        $logger->pushHandler(new Monolog\Handler\NullHandler());
-
-                       // enable the test handler
-                       $fileHandler = new Monolog\Handler\TestHandler();
-                       $formatter = new Monolog\Formatter\LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
-                       $fileHandler->setFormatter($formatter);
-
-                       $logger->pushHandler($fileHandler);
-
-                       return $fileHandler;
-               } else {
-                       throw new InternalServerErrorException('Logger instance incompatible for MonologFactory');
                }
        }
 }
diff --git a/src/Factory/ProfilerFactory.php b/src/Factory/ProfilerFactory.php
new file mode 100644 (file)
index 0000000..26a1566
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+namespace Friendica\Factory;
+
+use Friendica\Core\Config\Cache\IConfigCache;
+use Friendica\Util\Profiler;
+
+class ProfilerFactory
+{
+       /**
+        * Creates a Profiler for the current execution
+        *
+        * @param IConfigCache     $configCache The configuration cache
+        *
+        * @return Profiler
+        */
+       public static function create(IConfigCache $configCache)
+       {
+               $enabled = $configCache->get('system', 'profiler');
+               $enabled = isset($enabled) && $enabled !== '!<unset>!';
+               $renderTime = $configCache->get('rendertime', 'callstack');
+               $renderTime = isset($renderTime) && $renderTime !== '!<unset>!';
+
+               return new Profiler($enabled, $renderTime);
+       }
+}
index 6948dee6e0c52255c1f30d46c20c91b94a673769..3414e887fa93438b89253a565751ad178a0273de 100644 (file)
@@ -75,7 +75,7 @@ class Install extends BaseModule
                                $dbdata  = Strings::escapeTags(trim(defaults($_POST, 'dbdata', '')));
 
                                // If we cannot connect to the database, return to the previous step
-                               if (!self::$installer->checkDB($a->getConfig(), $dbhost, $dbuser, $dbpass, $dbdata)) {
+                               if (!self::$installer->checkDB($a->getConfigCache(), $a->getProfiler(), $dbhost, $dbuser, $dbpass, $dbdata)) {
                                        self::$currentWizardStep = self::DATABASE_CONFIG;
                                }
 
@@ -92,7 +92,7 @@ class Install extends BaseModule
                                $adminmail = Strings::escapeTags(trim(defaults($_POST, 'adminmail', '')));
 
                                // If we cannot connect to the database, return to the Database config wizard
-                               if (!self::$installer->checkDB($a->getConfig(), $dbhost, $dbuser, $dbpass, $dbdata)) {
+                               if (!self::$installer->checkDB($a->getConfigCache(), $a->getProfiler(), $dbhost, $dbuser, $dbpass, $dbdata)) {
                                        self::$currentWizardStep = self::DATABASE_CONFIG;
                                        return;
                                }
index 9143c23c16b3d2d15f095a097832df604365d6d1..45c8bedeaf58397abe15b1b7684a009156f63cad 100644 (file)
@@ -5,6 +5,7 @@
  */
 namespace Friendica\Object;
 
+use Exception;
 use Friendica\App;
 use Friendica\Core\Cache;
 use Friendica\Core\Config;
@@ -14,7 +15,6 @@ use Friendica\Core\System;
 use Friendica\Database\DBA;
 use Friendica\Model\Photo;
 use Friendica\Util\Network;
-use Exception;
 use Imagick;
 use ImagickPixel;
 
@@ -656,7 +656,7 @@ class Image
 
                $stamp1 = microtime(true);
                file_put_contents($path, $string);
-               $a->saveTimestamp($stamp1, "file");
+               $a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
        }
 
        /**
@@ -802,7 +802,7 @@ class Image
                                        $a = \get_app();
                                        $stamp1 = microtime(true);
                                        file_put_contents($tempfile, $img_str);
-                                       $a->saveTimestamp($stamp1, "file");
+                                       $a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
 
                                        $data = getimagesize($tempfile);
                                        unlink($tempfile);
@@ -910,7 +910,7 @@ class Image
 
                        $stamp1 = microtime(true);
                        $imagedata = @file_get_contents($url);
-                       $a->saveTimestamp($stamp1, "file");
+                       $a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
                }
 
                $maximagesize = Config::get('system', 'maximagesize');
@@ -924,7 +924,7 @@ class Image
 
                $stamp1 = microtime(true);
                file_put_contents($tempfile, $imagedata);
-               $a->saveTimestamp($stamp1, "file");
+               $a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
 
                $data = getimagesize($tempfile);
 
index de4b45da9a35bcf7c60572b140af0c8ac13b17c6..cda8c9a71d7113ddb0812af350195943425cf6d8 100644 (file)
@@ -4,13 +4,13 @@
  */
 namespace Friendica\Util;
 
+use DOMDocument;
+use DomXPath;
+use Friendica\Core\Config;
 use Friendica\Core\Hook;
 use Friendica\Core\Logger;
 use Friendica\Core\System;
-use Friendica\Core\Config;
 use Friendica\Network\CurlResult;
-use DOMDocument;
-use DomXPath;
 
 class Network
 {
@@ -232,7 +232,7 @@ class Network
 
                @curl_close($ch);
 
-               $a->saveTimestamp($stamp1, 'network');
+               $a->getProfiler()->saveTimestamp($stamp1, 'network', System::callstack());
 
                return $curlResponse;
        }
@@ -334,7 +334,7 @@ class Network
 
                curl_close($ch);
 
-               $a->saveTimestamp($stamp1, 'network');
+               $a->getProfiler()->saveTimestamp($stamp1, 'network', System::callstack());
 
                Logger::log('post_url: end ' . $url, Logger::DATA);
 
@@ -641,7 +641,7 @@ class Network
                $http_code = $curl_info['http_code'];
                curl_close($ch);
 
-               $a->saveTimestamp($stamp1, "network");
+               $a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack());
 
                if ($http_code == 0) {
                        return $url;
@@ -683,7 +683,7 @@ class Network
                $body = curl_exec($ch);
                curl_close($ch);
 
-               $a->saveTimestamp($stamp1, "network");
+               $a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack());
 
                if (trim($body) == "") {
                        return $url;
diff --git a/src/Util/Profiler.php b/src/Util/Profiler.php
new file mode 100644 (file)
index 0000000..2d3da3a
--- /dev/null
@@ -0,0 +1,239 @@
+<?php
+
+namespace Friendica\Util;
+
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\ContainerInterface;
+use Psr\Container\NotFoundExceptionInterface;
+use Psr\Log\LoggerInterface;
+
+/**
+ * A class to store profiling data
+ * It can handle different logging data for specific functions or global performance measures
+ *
+ * It stores the data as log entries (@see LoggerInterface )
+ */
+class Profiler implements ContainerInterface
+{
+       /**
+        * @var array The global performance array
+        */
+       private $performance;
+       /**
+        * @var array The function specific callstack
+        */
+       private $callstack;
+       /**
+        * @var bool True, if the Profiler is enabled
+        */
+       private $enabled;
+       /**
+        * @var bool True, if the Profiler should measure the whole rendertime including functions
+        */
+       private $rendertime;
+
+       /**
+        * @param bool $enabled           True, if the Profiler is enabled
+        * @param bool $renderTime        True, if the Profiler should measure the whole rendertime including functions
+        */
+       public function __construct($enabled = false, $renderTime = false)
+       {
+               $this->enabled = $enabled;
+               $this->rendertime = $renderTime;
+               $this->reset();
+       }
+
+       /**
+        * Saves a timestamp for a value - f.e. a call
+        * Necessary for profiling Friendica
+        *
+        * @param int $timestamp the Timestamp
+        * @param string $value A value to profile
+        * @param string $callstack The callstack of the current profiling data
+        */
+       public function saveTimestamp($timestamp, $value, $callstack = '')
+       {
+               if (!$this->enabled) {
+                       return;
+               }
+
+               $duration = (float) (microtime(true) - $timestamp);
+
+               if (!isset($this->performance[$value])) {
+                       // Prevent ugly E_NOTICE
+                       $this->performance[$value] = 0;
+               }
+
+               $this->performance[$value] += (float) $duration;
+               $this->performance['marktime'] += (float) $duration;
+
+               if (!isset($this->callstack[$value][$callstack])) {
+                       // Prevent ugly E_NOTICE
+                       $this->callstack[$value][$callstack] = 0;
+               }
+
+               $this->callstack[$value][$callstack] += (float) $duration;
+       }
+
+       /**
+        * Resets the performance and callstack profiling
+        */
+       public function reset()
+       {
+               $this->resetPerformance();
+               $this->resetCallstack();
+       }
+
+       /**
+        * Resets the performance profiling data
+        */
+       public function resetPerformance()
+       {
+               $this->performance = [];
+               $this->performance['start'] = microtime(true);
+               $this->performance['database'] = 0;
+               $this->performance['database_write'] = 0;
+               $this->performance['cache'] = 0;
+               $this->performance['cache_write'] = 0;
+               $this->performance['network'] = 0;
+               $this->performance['file'] = 0;
+               $this->performance['rendering'] = 0;
+               $this->performance['parser'] = 0;
+               $this->performance['marktime'] = 0;
+               $this->performance['marktime'] = microtime(true);
+       }
+
+       /**
+        * Resets the callstack profiling data
+        */
+       public function resetCallstack()
+       {
+               $this->callstack = [];
+               $this->callstack['database'] = [];
+               $this->callstack['database_write'] = [];
+               $this->callstack['cache'] = [];
+               $this->callstack['cache_write'] = [];
+               $this->callstack['network'] = [];
+               $this->callstack['file'] = [];
+               $this->callstack['rendering'] = [];
+               $this->callstack['parser'] = [];
+       }
+
+       /**
+        * Save the current profiling data to a log entry
+        *
+        * @param LoggerInterface $logger The logger to save the current log
+        * @param string          $message Additional message for the log
+        */
+       public function saveLog(LoggerInterface $logger, $message = '')
+       {
+               // Write down the performance values into the log
+               if (!$this->enabled) {
+                       return;
+               }
+               $duration = microtime(true) - $this->get('start');
+               $logger->info(
+                       $message,
+                       [
+                               'action' => 'profiling',
+                               'database_read' => round($this->get('database') - $this->get('database_write'), 3),
+                               'database_write' => round($this->get('database_write'), 3),
+                               'cache_read' => round($this->get('cache'), 3),
+                               'cache_write' => round($this->get('cache_write'), 3),
+                               'network_io' => round($this->get('network'), 2),
+                               'file_io' => round($this->get('file'), 2),
+                               'other_io' => round($duration - ($this->get('database')
+                                               + $this->get('cache') + $this->get('cache_write')
+                                               + $this->get('network') + $this->get('file')), 2),
+                               'total' => round($duration, 2)
+                       ]
+               );
+
+               if (!$this->rendertime) {
+                       return;
+               }
+               
+               $o = '';
+               if (isset($this->callstack["database"])) {
+                       $o .= "\nDatabase Read:\n";
+                       foreach ($this->callstack["database"] as $func => $time) {
+                               $time = round($time, 3);
+                               if ($time > 0) {
+                                       $o .= $func . ": " . $time . "\n";
+                               }
+                       }
+               }
+               if (isset($this->callstack["database_write"])) {
+                       $o .= "\nDatabase Write:\n";
+                       foreach ($this->callstack["database_write"] as $func => $time) {
+                               $time = round($time, 3);
+                               if ($time > 0) {
+                                       $o .= $func . ": " . $time . "\n";
+                               }
+                       }
+               }
+               if (isset($this->callstack["cache"])) {
+                       $o .= "\nCache Read:\n";
+                       foreach ($this->callstack["cache"] as $func => $time) {
+                               $time = round($time, 3);
+                               if ($time > 0) {
+                                       $o .= $func . ": " . $time . "\n";
+                               }
+                       }
+               }
+               if (isset($this->callstack["cache_write"])) {
+                       $o .= "\nCache Write:\n";
+                       foreach ($this->callstack["cache_write"] as $func => $time) {
+                               $time = round($time, 3);
+                               if ($time > 0) {
+                                       $o .= $func . ": " . $time . "\n";
+                               }
+                       }
+               }
+               if (isset($this->callstack["network"])) {
+                       $o .= "\nNetwork:\n";
+                       foreach ($this->callstack["network"] as $func => $time) {
+                               $time = round($time, 3);
+                               if ($time > 0) {
+                                       $o .= $func . ": " . $time . "\n";
+                               }
+                       }
+               }
+               $logger->info($message . ": " . $o, ['action' => 'profiling']);
+       }
+
+       /**
+        * Finds an entry of the container by its identifier and returns it.
+        *
+        * @param string $id Identifier of the entry to look for.
+        *
+        * @throws NotFoundExceptionInterface  No entry was found for **this** identifier.
+        * @throws ContainerExceptionInterface Error while retrieving the entry.
+        *
+        * @return int Entry.
+        */
+       public function get($id)
+       {
+               if (!$this->has($id)) {
+                       return 0;
+               } else {
+                       return $this->performance[$id];
+               }
+       }
+
+       /**
+        * Returns true if the container can return an entry for the given identifier.
+        * Returns false otherwise.
+        *
+        * `has($id)` returning true does not mean that `get($id)` will not throw an exception.
+        * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
+        *
+        * @param string $id Identifier of the entry to look for.
+        *
+        * @return bool
+        */
+       public function has($id)
+       {
+               return isset($this->performance[$id]);
+       }
+}
index 79af5b5468a9495f86d390ceda58d1afdc4d64eb..dde61e856b8d6392f525df1c4461559d1278ea00 100644 (file)
@@ -5,10 +5,11 @@
 
 namespace Friendica\Test;
 
-use Friendica\Core\Config;
+use Friendica\Core\Config\Cache;
 use Friendica\Database\DBA;
 use Friendica\Factory;
 use Friendica\Util\BasePath;
+use Friendica\Util\Profiler;
 use PHPUnit\DbUnit\DataSet\YamlDataSet;
 use PHPUnit\DbUnit\TestCaseTrait;
 use PHPUnit_Extensions_Database_DB_IDatabaseConnection;
@@ -40,11 +41,14 @@ abstract class DatabaseTest extends MockedTest
                }
 
                $basedir = BasePath::create(dirname(__DIR__));
-               $configLoader = new Config\ConfigCacheLoader($basedir);
+               $configLoader = new Cache\ConfigCacheLoader($basedir);
                $config = Factory\ConfigFactory::createCache($configLoader);
 
+               $profiler = \Mockery::mock(Profiler::class);
+
                DBA::connect(
                        $config,
+                       $profiler,
                        getenv('MYSQL_HOST'),
                        getenv('MYSQL_USERNAME'),
                        getenv('MYSQL_PASSWORD'),
index 18188239f1760ee2aff511f9a4a3a5524d10a270..817570dd58c948cd4418e3217e4a660f3d6d1ac2 100644 (file)
@@ -5,8 +5,8 @@ namespace Friendica\Test\Util;
 use Friendica\App;
 use Friendica\BaseObject;
 use Friendica\Core\Config;
-use Friendica\Core\Config\ConfigCache;
 use Friendica\Render\FriendicaSmartyEngine;
+use Friendica\Util\Profiler;
 use Mockery\MockInterface;
 use org\bovigo\vfs\vfsStreamDirectory;
 
@@ -21,74 +21,83 @@ trait AppMockTrait
        protected $app;
 
        /**
-        * @var MockInterface|ConfigCache The mocked Config Cache
+        * @var MockInterface|Config\Configuration The mocked Config Cache
         */
-       protected $configCache;
+       protected $configMock;
+
+       /**
+        * @var MockInterface|Profiler The mocked profiler
+        */
+       protected $profilerMock;
 
        /**
         * Mock the App
         *
         * @param vfsStreamDirectory $root The root directory
-        * @param MockInterface|ConfigCache $config The config cache
         */
-       public function mockApp($root, $config)
+       public function mockApp($root)
        {
-               $this->configCache = $config;
+               $this->configMock = \Mockery::mock(Config\Cache\IConfigCache::class);
+               $configAdapterMock = \Mockery::mock(Config\Adapter\IConfigAdapter::class);
+               // Disable the adapter
+               $configAdapterMock->shouldReceive('isConnected')->andReturn(false);
+
+               $config = new Config\Configuration($this->configMock, $configAdapterMock);
+               // Initialize empty Config
+               Config::init($config);
+
                // Mocking App and most used functions
                $this->app = \Mockery::mock(App::class);
                $this->app
                        ->shouldReceive('getBasePath')
                        ->andReturn($root->url());
 
-               $config
+               $this->configMock
+                       ->shouldReceive('has')
+                       ->andReturn(true);
+               $this->configMock
                        ->shouldReceive('get')
                        ->with('database', 'hostname')
                        ->andReturn(getenv('MYSQL_HOST'));
-               $config
+               $this->configMock
                        ->shouldReceive('get')
                        ->with('database', 'username')
                        ->andReturn(getenv('MYSQL_USERNAME'));
-               $config
+               $this->configMock
                        ->shouldReceive('get')
                        ->with('database', 'password')
                        ->andReturn(getenv('MYSQL_PASSWORD'));
-               $config
+               $this->configMock
                        ->shouldReceive('get')
                        ->with('database', 'database')
                        ->andReturn(getenv('MYSQL_DATABASE'));
-               $config
+               $this->configMock
                        ->shouldReceive('get')
                        ->with('config', 'hostname')
                        ->andReturn('localhost');
-               $config
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('system', 'theme', NULL)
+                       ->with('system', 'theme')
                        ->andReturn('system_theme');
 
-               $this->app
-                       ->shouldReceive('getConfig')
-                       ->andReturn($config);
+               $this->profilerMock = \Mockery::mock(Profiler::class);
+               $this->profilerMock->shouldReceive('saveTimestamp');
 
+               $this->app
+                       ->shouldReceive('getConfigCache')
+                       ->andReturn($this->configMock);
                $this->app
                        ->shouldReceive('getTemplateEngine')
                        ->andReturn(new FriendicaSmartyEngine());
                $this->app
                        ->shouldReceive('getCurrentTheme')
                        ->andReturn('Smarty3');
-               $this->app
-                       ->shouldReceive('saveTimestamp')
-                       ->andReturn(true);
                $this->app
                        ->shouldReceive('getBaseUrl')
                        ->andReturn('http://friendica.local');
-
-               // Initialize empty Config
-               Config::init($config);
-               $configAdapter = \Mockery::mock('Friendica\Core\Config\IConfigAdapter');
-               $configAdapter
-                       ->shouldReceive('isConnected')
-                       ->andReturn(false);
-               Config::setAdapter($configAdapter);
+               $this->app
+                       ->shouldReceive('getProfiler')
+                       ->andReturn($this->profilerMock);
 
                BaseObject::setApp($this->app);
        }
index 87c120d3f22337d0e5c8b83ee96ebaa681bb537d..92ec412cb7ed4bec698c49c768248b2efe9d67a1 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace Friendica\Test\Util;
 
+use Friendica\Database\DBStructure;
 use Mockery\MockInterface;
 
 /**
@@ -16,6 +17,7 @@ trait DBStructureMockTrait
 
        /**
         * Mocking DBStructure::update()
+        * @see DBStructure::update();
         *
         * @param array $args The arguments for the update call
         * @param bool $return True, if the connect was successful, otherwise false
index be70d923bd4866c42e3f084cf4a543cb5ef72f2a..289b3fcea54f278db4f5b099817d7dd7109b0f0f 100644 (file)
@@ -7,6 +7,7 @@ namespace Friendica\Test;
 
 use Friendica\App;
 use Friendica\Core\Config;
+use Friendica\Core\Config\Cache;
 use Friendica\Core\PConfig;
 use Friendica\Core\Protocol;
 use Friendica\Core\System;
@@ -36,11 +37,14 @@ class ApiTest extends DatabaseTest
        public function setUp()
        {
                $basedir = BasePath::create(dirname(__DIR__) . '/../');
-               $configLoader = new Config\ConfigCacheLoader($basedir);
-               $config = Factory\ConfigFactory::createCache($configLoader);
+               $configLoader = new Cache\ConfigCacheLoader($basedir);
+               $configCache = Factory\ConfigFactory::createCache($configLoader);
+               $profiler = Factory\ProfilerFactory::create($configCache);
+               Factory\DBFactory::init($configCache, $profiler, $_SERVER);
+               $config = Factory\ConfigFactory::createConfig($configCache);
+               Factory\ConfigFactory::createPConfig($configCache);
                $logger = Factory\LoggerFactory::create('test', $config);
-               $this->app = new App($config, $logger, false);
-               $this->logOutput = FActory\LoggerFactory::enableTest($this->app->getLogger());
+               $this->app = new App($config, $logger, $profiler, false);
 
                parent::setUp();
 
index 19dad07cd6eae94af0e590cc0f410889eaa6e38b..9059e8bebf4ad6b6d1ec29812dcc239a9e774f7e 100644 (file)
@@ -90,19 +90,14 @@ class ModeTest extends MockedTest
                $this->mockConnected(true, 1);
                $this->mockFetchFirst('SHOW TABLES LIKE \'config\'', true, 1);
 
-               $config = \Mockery::mock('Friendica\Core\Config\ConfigCache');
+               $config = \Mockery::mock(Config\Configuration::class);
                $config
                        ->shouldReceive('get')
-                       ->with('system', 'maintenance', null)
+                       ->with('system', 'maintenance', null, false)
                        ->andReturn(true)
                        ->once();
                // Initialize empty Config
                Config::init($config);
-               $configAdapter = \Mockery::mock('Friendica\Core\Config\IConfigAdapter');
-               $configAdapter
-                       ->shouldReceive('isConnected')
-                       ->andReturn(false);
-               Config::setAdapter($configAdapter);
 
                $mode = new Mode($this->root->url());
                $mode->determine();
@@ -123,19 +118,14 @@ class ModeTest extends MockedTest
                $this->mockConnected(true, 1);
                $this->mockFetchFirst('SHOW TABLES LIKE \'config\'', true, 1);
 
-               $config = \Mockery::mock('Friendica\Core\Config\ConfigCache');
+               $config = \Mockery::mock(Config\Configuration::class);
                $config
                        ->shouldReceive('get')
-                       ->with('system', 'maintenance', null)
+                       ->with('system', 'maintenance', null, false)
                        ->andReturn(false)
                        ->once();
                // Initialize empty Config
                Config::init($config);
-               $configAdapter = \Mockery::mock('Friendica\Core\Config\IConfigAdapter');
-               $configAdapter
-                       ->shouldReceive('isConnected')
-                       ->andReturn(false);
-               Config::setAdapter($configAdapter);
 
                $mode = new Mode($this->root->url());
                $mode->determine();
index 784944c3a06425a35a6aa8b78da5f5245c6fa299..3341503915f4738e68cad7d74e6cfaab641e72e6 100644 (file)
@@ -31,8 +31,7 @@ class BaseObjectTest extends TestCase
        {
                $baseObject = new BaseObject();
                $this->setUpVfsDir();
-               $configMock = \Mockery::mock('Friendica\Core\Config\ConfigCache');
-               $this->mockApp($this->root, $configMock);
+               $this->mockApp($this->root);
 
                $this->assertNull($baseObject->setApp($this->app));
                $this->assertEquals($this->app, $baseObject->getApp());
index e8bd65cbfe5670c0865dd28537b6f39b67684c44..ef97f5a172214ea16ed325ca79b7ff8cb5f2d027 100644 (file)
@@ -67,8 +67,7 @@ abstract class CacheTest extends MockedTest
        protected function setUp()
        {
                $this->setUpVfsDir();
-               $configMock = \Mockery::mock('Friendica\Core\Config\ConfigCache');
-               $this->mockApp($this->root, $configMock);
+               $this->mockApp($this->root);
                $this->app
                        ->shouldReceive('getHostname')
                        ->andReturn('friendica.local');
index 7832344a89522071a47da49efada0689d9e8256c..f9df9eaba089b996ab62ed108908801451f9f486 100644 (file)
@@ -12,14 +12,14 @@ class MemcacheCacheDriverTest extends MemoryCacheTest
 {
        protected function getInstance()
        {
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('system', 'memcache_host', NULL)
+                       ->with('system', 'memcache_host')
                        ->andReturn('localhost');
 
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('system', 'memcache_port', NULL)
+                       ->with('system', 'memcache_port')
                        ->andReturn(11211);
 
                $this->cache = CacheDriverFactory::create('memcache');
index fe401f97dd40d95d718ebf8fe5959884684300de..4e16ef947f7fadd4373d19432cca98e6f267eb1a 100644 (file)
@@ -12,9 +12,9 @@ class MemcachedCacheDriverTest extends MemoryCacheTest
 {
        protected function getInstance()
        {
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('system', 'memcached_hosts', NULL)
+                       ->with('system', 'memcached_hosts')
                        ->andReturn([0 => 'localhost, 11211']);
 
                $this->cache = CacheDriverFactory::create('memcached');
index 0a3dba439d83ace9f5b254667e06d73e50de131f..20fe7eb53f299fcaa8e7fb9dc3611fc2d916b805 100644 (file)
@@ -12,14 +12,14 @@ class RedisCacheDriverTest extends MemoryCacheTest
 {
        protected function getInstance()
        {
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('system', 'redis_host', NULL)
+                       ->with('system', 'redis_host')
                        ->andReturn('localhost');
 
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('system', 'redis_port', NULL)
+                       ->with('system', 'redis_port')
                        ->andReturn(null);
 
                $this->cache = CacheDriverFactory::create('redis');
diff --git a/tests/src/Core/Config/Cache/ConfigCacheLoaderTest.php b/tests/src/Core/Config/Cache/ConfigCacheLoaderTest.php
new file mode 100644 (file)
index 0000000..f91f267
--- /dev/null
@@ -0,0 +1,188 @@
+<?php
+
+namespace Friendica\Test\Core\Config\Cache;
+
+use Friendica\Core\Config\Cache\ConfigCache;
+use Friendica\Core\Config\Cache\ConfigCacheLoader;
+use Friendica\Test\MockedTest;
+use Friendica\Test\Util\VFSTrait;
+use org\bovigo\vfs\vfsStream;
+
+class ConfigCacheLoaderTest extends MockedTest
+{
+       use VFSTrait;
+
+       protected function setUp()
+       {
+               parent::setUp();
+
+               $this->setUpVfsDir();
+       }
+
+       /**
+        * Test the loadConfigFiles() method with default values
+        */
+       public function testLoadConfigFiles()
+       {
+               $configCacheLoader = new ConfigCacheLoader($this->root->url());
+               $configCache = new ConfigCache();
+
+               $configCacheLoader->loadConfigFiles($configCache);
+
+               $this->assertEquals($this->root->url(), $configCache->get('system', 'basepath'));
+       }
+
+       /**
+        * Test the loadConfigFiles() method with a wrong local.config.php
+        * @expectedException \Exception
+        * @expectedExceptionMessageRegExp /Error loading config file \w+/
+        */
+       public function testLoadConfigWrong()
+       {
+               $this->delConfigFile('local.config.php');
+
+               vfsStream::newFile('local.config.php')
+                       ->at($this->root->getChild('config'))
+                       ->setContent('<?php return true;');
+
+               $configCacheLoader = new ConfigCacheLoader($this->root->url());
+               $configCache = new ConfigCache();
+
+               $configCacheLoader->loadConfigFiles($configCache);
+       }
+
+       /**
+        * Test the loadConfigFiles() method with a local.config.php file
+        */
+       public function testLoadConfigFilesLocal()
+       {
+               $this->delConfigFile('local.config.php');
+
+               $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
+                       '..' . DIRECTORY_SEPARATOR .
+                       '..' . DIRECTORY_SEPARATOR .
+                       '..' . DIRECTORY_SEPARATOR .
+                       'datasets' . DIRECTORY_SEPARATOR .
+                       'config' . DIRECTORY_SEPARATOR .
+                       'local.config.php';
+
+               vfsStream::newFile('local.config.php')
+                       ->at($this->root->getChild('config'))
+                       ->setContent(file_get_contents($file));
+
+               $configCacheLoader = new ConfigCacheLoader($this->root->url());
+               $configCache = new ConfigCache();
+
+               $configCacheLoader->loadConfigFiles($configCache);
+
+               $this->assertEquals('testhost', $configCache->get('database', 'hostname'));
+               $this->assertEquals('testuser', $configCache->get('database', 'username'));
+               $this->assertEquals('testpw', $configCache->get('database', 'password'));
+               $this->assertEquals('testdb', $configCache->get('database', 'database'));
+
+               $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
+               $this->assertEquals('Friendica Social Network', $configCache->get('config', 'sitename'));
+       }
+
+       /**
+        * Test the loadConfigFile() method with a local.ini.php file
+        */
+       public function testLoadConfigFilesINI()
+       {
+               $this->delConfigFile('local.config.php');
+
+               $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
+                       '..' . DIRECTORY_SEPARATOR .
+                       '..' . DIRECTORY_SEPARATOR .
+                       '..' . DIRECTORY_SEPARATOR .
+                       'datasets' . DIRECTORY_SEPARATOR .
+                       'config' . DIRECTORY_SEPARATOR .
+                       'local.ini.php';
+
+               vfsStream::newFile('local.ini.php')
+                       ->at($this->root->getChild('config'))
+                       ->setContent(file_get_contents($file));
+
+               $configCacheLoader = new ConfigCacheLoader($this->root->url());
+               $configCache = new ConfigCache();
+
+               $configCacheLoader->loadConfigFiles($configCache);
+
+               $this->assertEquals('testhost', $configCache->get('database', 'hostname'));
+               $this->assertEquals('testuser', $configCache->get('database', 'username'));
+               $this->assertEquals('testpw', $configCache->get('database', 'password'));
+               $this->assertEquals('testdb', $configCache->get('database', 'database'));
+
+               $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
+       }
+
+       /**
+        * Test the loadConfigFile() method with a .htconfig.php file
+        */
+       public function testLoadConfigFilesHtconfig()
+       {
+               $this->delConfigFile('local.config.php');
+
+               $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
+                       '..' . DIRECTORY_SEPARATOR .
+                       '..' . DIRECTORY_SEPARATOR .
+                       '..' . DIRECTORY_SEPARATOR .
+                       'datasets' . DIRECTORY_SEPARATOR .
+                       'config' . DIRECTORY_SEPARATOR .
+                       '.htconfig.test.php';
+
+               vfsStream::newFile('.htconfig.php')
+                       ->at($this->root)
+                       ->setContent(file_get_contents($file));
+
+               $configCacheLoader = new ConfigCacheLoader($this->root->url());
+               $configCache = new ConfigCache();
+
+               $configCacheLoader->loadConfigFiles($configCache);
+
+               $this->assertEquals('testhost', $configCache->get('database', 'hostname'));
+               $this->assertEquals('testuser', $configCache->get('database', 'username'));
+               $this->assertEquals('testpw', $configCache->get('database', 'password'));
+               $this->assertEquals('testdb', $configCache->get('database', 'database'));
+
+               $this->assertEquals('/var/run/friendica.pid', $configCache->get('system', 'pidfile'));
+               $this->assertEquals('Europe/Berlin', $configCache->get('system', 'default_timezone'));
+               $this->assertEquals('fr', $configCache->get('system', 'language'));
+       }
+
+       public function testLoadAddonConfig()
+       {
+               $structure = [
+                       'addon' => [
+                               'test' => [
+                                       'config' => [],
+                               ],
+                       ],
+               ];
+
+               vfsStream::create($structure, $this->root);
+
+               $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
+                       '..' . DIRECTORY_SEPARATOR .
+                       '..' . DIRECTORY_SEPARATOR .
+                       '..' . DIRECTORY_SEPARATOR .
+                       'datasets' . DIRECTORY_SEPARATOR .
+                       'config' . DIRECTORY_SEPARATOR .
+                       'local.config.php';
+
+               vfsStream::newFile('test.config.php')
+                       ->at($this->root->getChild('addon')->getChild('test')->getChild('config'))
+                       ->setContent(file_get_contents($file));
+
+               $configCacheLoader = new ConfigCacheLoader($this->root->url());
+
+               $conf = $configCacheLoader->loadAddonConfig('test');
+
+               $this->assertEquals('testhost', $conf['database']['hostname']);
+               $this->assertEquals('testuser', $conf['database']['username']);
+               $this->assertEquals('testpw', $conf['database']['password']);
+               $this->assertEquals('testdb', $conf['database']['database']);
+
+               $this->assertEquals('admin@test.it', $conf['config']['admin_email']);
+       }
+}
diff --git a/tests/src/Core/Config/Cache/ConfigCacheTest.php b/tests/src/Core/Config/Cache/ConfigCacheTest.php
new file mode 100644 (file)
index 0000000..ac9fae5
--- /dev/null
@@ -0,0 +1,283 @@
+<?php
+
+namespace Friendica\Test\Core\Config\Cache;
+
+use Friendica\Core\Config\Cache\ConfigCache;
+use Friendica\Test\MockedTest;
+
+class ConfigCacheTest extends MockedTest
+{
+       public function dataTests()
+       {
+               return [
+                       'normal' => [
+                               'data' => [
+                                       'system' => [
+                                               'test' => 'it',
+                                               'boolTrue' => true,
+                                               'boolFalse' => false,
+                                               'int' => 235,
+                                               'dec' => 2.456,
+                                               'array' => ['1', 2, '3', true, false],
+                                       ],
+                                       'config' => [
+                                               'a' => 'value',
+                                       ],
+                               ]
+                       ]
+               ];
+       }
+
+       private function assertConfigValues($data, ConfigCache $configCache, $uid = null)
+       {
+               foreach ($data as $cat => $values) {
+                       foreach ($values as $key => $value) {
+                               if (isset($uid)) {
+                                       $this->assertEquals($data[$cat][$key], $configCache->getP($uid, $cat, $key));
+                               } else {
+                                       $this->assertEquals($data[$cat][$key], $configCache->get($cat, $key));
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Test the loadConfigArray() method without override
+        * @dataProvider dataTests
+        */
+       public function testLoadConfigArray($data)
+       {
+               $configCache = new ConfigCache();
+               $configCache->load($data);
+
+               $this->assertConfigValues($data, $configCache);
+       }
+
+       /**
+        * Test the loadConfigArray() method with overrides
+        * @dataProvider dataTests
+        */
+       public function testLoadConfigArrayOverride($data)
+       {
+               $override = [
+                       'system' => [
+                               'test' => 'not',
+                               'boolTrue' => false,
+                       ]
+               ];
+
+               $configCache = new ConfigCache();
+               $configCache->load($data);
+               $configCache->load($override);
+
+               $this->assertConfigValues($data, $configCache);
+
+               // override the value
+               $configCache->load($override, true);
+
+               $this->assertEquals($override['system']['test'], $configCache->get('system', 'test'));
+               $this->assertEquals($override['system']['boolTrue'], $configCache->get('system', 'boolTrue'));
+       }
+
+       /**
+        * Test the loadConfigArray() method with wrong/empty datasets
+        */
+       public function testLoadConfigArrayWrong()
+       {
+               $configCache = new ConfigCache();
+
+               // empty dataset
+               $configCache->load([]);
+               $this->assertEmpty($configCache->getAll());
+
+               // wrong dataset
+               $configCache->load(['system' => 'not_array']);
+               $this->assertEmpty($configCache->getAll());
+
+               // incomplete dataset (key is integer ID of the array)
+               $configCache->load(['system' => ['value']]);
+               $this->assertEquals('value', $configCache->get('system', 0));
+       }
+
+       /**
+        * Test the getAll() method
+        * @dataProvider dataTests
+        */
+       public function testGetAll($data)
+       {
+               $configCache = new ConfigCache();
+               $configCache->load($data);
+
+               $all = $configCache->getAll();
+
+               $this->assertContains($data['system'], $all);
+               $this->assertContains($data['config'], $all);
+       }
+
+       /**
+        * Test the set() and get() method
+        * @dataProvider dataTests
+        */
+       public function testSetGet($data)
+       {
+               $configCache = new ConfigCache();
+
+               foreach ($data as $cat => $values) {
+                       foreach ($values as $key => $value) {
+                               $configCache->set($cat, $key, $value);
+                       }
+               }
+
+               $this->assertConfigValues($data, $configCache);
+       }
+
+       /**
+        * Test the get() method without a value
+        */
+       public function testGetEmpty()
+       {
+               $configCache = new ConfigCache();
+
+               $this->assertEquals('!<unset>!', $configCache->get('something', 'value'));
+       }
+
+       /**
+        * Test the has() method
+        */
+       public function testHas()
+       {
+               $configCache = new ConfigCache();
+
+               $this->assertFalse($configCache->has('system', 'test'));
+               $this->assertFalse($configCache->has('system'));
+
+               $configCache->set('system', 'test', 'it');
+               $this->assertTrue($configCache->has('system', 'test'));
+               $this->assertTrue($configCache->has('system'));
+       }
+
+       /**
+        * Test the get() method with a category
+        */
+       public function testGetCat()
+       {
+               $configCache = new ConfigCache([
+                       'system' => [
+                               'key1' => 'value1',
+                               'key2' => 'value2',
+                       ],
+                       'config' => [
+                               'key3' => 'value3',
+                       ],
+               ]);
+
+               $this->assertTrue($configCache->has('system'));
+
+               $this->assertEquals([
+                       'key1' => 'value1',
+                       'key2' => 'value2',
+               ], $configCache->get('system'));
+       }
+
+       /**
+        * Test the delete() method
+        * @dataProvider dataTests
+        */
+       public function testDelete($data)
+       {
+               $configCache = new ConfigCache($data);
+
+               foreach ($data as $cat => $values) {
+                       foreach ($values as $key => $value) {
+                               $configCache->delete($cat, $key);
+                       }
+               }
+
+               $this->assertEmpty($configCache->getAll());
+       }
+
+       /**
+        * Test the setP() and getP() methods
+        * @dataProvider dataTests
+        */
+       public function testSetGetP($data)
+       {
+               $configCache = new ConfigCache();
+               $uid = 345;
+
+               foreach ($data as $cat => $values) {
+                       foreach ($values as $key => $value) {
+                               $configCache->setP($uid, $cat, $key, $value);
+                       }
+               }
+
+               $this->assertConfigValues($data, $configCache, $uid);
+       }
+
+
+       /**
+        * Test the getP() method with a category
+        */
+       public function testGetPCat()
+       {
+               $configCache = new ConfigCache();
+               $uid = 345;
+
+               $configCache->loadP($uid, [
+                       'system' => [
+                               'key1' => 'value1',
+                               'key2' => 'value2',
+                       ],
+                       'config' => [
+                               'key3' => 'value3',
+                       ],
+               ]);
+
+               $this->assertTrue($configCache->hasP($uid,'system'));
+
+               $this->assertEquals([
+                       'key1' => 'value1',
+                       'key2' => 'value2',
+               ], $configCache->get($uid, 'system'));
+       }
+
+       /**
+        * Test the deleteP() method
+        * @dataProvider dataTests
+        */
+       public function testDeleteP($data)
+       {
+               $configCache = new ConfigCache();
+               $uid = 345;
+
+               foreach ($data as $cat => $values) {
+                       foreach ($values as $key => $value) {
+                               $configCache->setP($uid, $cat, $key, $value);
+                       }
+               }
+
+               foreach ($data as $cat => $values) {
+                       foreach ($values as $key => $value) {
+                               $configCache->deleteP($uid, $cat, $key);
+                       }
+               }
+
+               $this->assertEmpty($configCache->getAll());
+       }
+
+       /**
+        * Test the hasP() method
+        */
+       public function testHasP()
+       {
+               $configCache = new ConfigCache();
+               $uid = 345;
+
+               $this->assertFalse($configCache->hasP($uid, 'system', 'test'));
+               $this->assertFalse($configCache->hasP($uid, 'system'));
+
+               $configCache->setP($uid, 'system', 'test', 'it');
+               $this->assertTrue($configCache->hasP($uid, 'system', 'test'));
+               $this->assertTrue($configCache->hasP($uid, 'system'));
+       }
+}
diff --git a/tests/src/Core/Config/ConfigCacheLoaderTest.php b/tests/src/Core/Config/ConfigCacheLoaderTest.php
deleted file mode 100644 (file)
index 6be89bc..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-<?php
-
-namespace Friendica\Test\Core\Config;
-
-use Friendica\Core\Config\ConfigCache;
-use Friendica\Core\Config\ConfigCacheLoader;
-use Friendica\Test\MockedTest;
-use Friendica\Test\Util\VFSTrait;
-use org\bovigo\vfs\vfsStream;
-
-class ConfigCacheLoaderTest extends MockedTest
-{
-       use VFSTrait;
-
-       protected function setUp()
-       {
-               parent::setUp();
-
-               $this->setUpVfsDir();
-       }
-
-       /**
-        * Test the loadConfigFiles() method with default values
-        */
-       public function testLoadConfigFiles()
-       {
-               $configCacheLoader = new ConfigCacheLoader($this->root->url());
-               $configCache = new ConfigCache();
-
-               $configCacheLoader->loadConfigFiles($configCache);
-
-               $this->assertEquals($this->root->url(), $configCache->get('system', 'basepath'));
-       }
-
-       /**
-        * Test the loadConfigFiles() method with a wrong local.config.php
-        * @expectedException \Exception
-        * @expectedExceptionMessageRegExp /Error loading config file \w+/
-        */
-       public function testLoadConfigWrong()
-       {
-               $this->delConfigFile('local.config.php');
-
-               vfsStream::newFile('local.config.php')
-                       ->at($this->root->getChild('config'))
-                       ->setContent('<?php return true;');
-
-               $configCacheLoader = new ConfigCacheLoader($this->root->url());
-               $configCache = new ConfigCache();
-
-               $configCacheLoader->loadConfigFiles($configCache);
-       }
-
-       /**
-        * Test the loadConfigFiles() method with a local.config.php file
-        */
-       public function testLoadConfigFilesLocal()
-       {
-               $this->delConfigFile('local.config.php');
-
-               $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
-                       '..' . DIRECTORY_SEPARATOR .
-                       '..' . DIRECTORY_SEPARATOR .
-                       'datasets' . DIRECTORY_SEPARATOR .
-                       'config' . DIRECTORY_SEPARATOR .
-                       'local.config.php';
-
-               vfsStream::newFile('local.config.php')
-                       ->at($this->root->getChild('config'))
-                       ->setContent(file_get_contents($file));
-
-               $configCacheLoader = new ConfigCacheLoader($this->root->url());
-               $configCache = new ConfigCache();
-
-               $configCacheLoader->loadConfigFiles($configCache);
-
-               $this->assertEquals('testhost', $configCache->get('database', 'hostname'));
-               $this->assertEquals('testuser', $configCache->get('database', 'username'));
-               $this->assertEquals('testpw', $configCache->get('database', 'password'));
-               $this->assertEquals('testdb', $configCache->get('database', 'database'));
-
-               $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
-               $this->assertEquals('Friendica Social Network', $configCache->get('config', 'sitename'));
-       }
-
-       /**
-        * Test the loadConfigFile() method with a local.ini.php file
-        */
-       public function testLoadConfigFilesINI()
-       {
-               $this->delConfigFile('local.config.php');
-
-               $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
-                       '..' . DIRECTORY_SEPARATOR .
-                       '..' . DIRECTORY_SEPARATOR .
-                       'datasets' . DIRECTORY_SEPARATOR .
-                       'config' . DIRECTORY_SEPARATOR .
-                       'local.ini.php';
-
-               vfsStream::newFile('local.ini.php')
-                       ->at($this->root->getChild('config'))
-                       ->setContent(file_get_contents($file));
-
-               $configCacheLoader = new ConfigCacheLoader($this->root->url());
-               $configCache = new ConfigCache();
-
-               $configCacheLoader->loadConfigFiles($configCache);
-
-               $this->assertEquals('testhost', $configCache->get('database', 'hostname'));
-               $this->assertEquals('testuser', $configCache->get('database', 'username'));
-               $this->assertEquals('testpw', $configCache->get('database', 'password'));
-               $this->assertEquals('testdb', $configCache->get('database', 'database'));
-
-               $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
-       }
-
-       /**
-        * Test the loadConfigFile() method with a .htconfig.php file
-        */
-       public function testLoadConfigFilesHtconfig()
-       {
-               $this->delConfigFile('local.config.php');
-
-               $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
-                       '..' . DIRECTORY_SEPARATOR .
-                       '..' . DIRECTORY_SEPARATOR .
-                       'datasets' . DIRECTORY_SEPARATOR .
-                       'config' . DIRECTORY_SEPARATOR .
-                       '.htconfig.test.php';
-
-               vfsStream::newFile('.htconfig.php')
-                       ->at($this->root)
-                       ->setContent(file_get_contents($file));
-
-               $configCacheLoader = new ConfigCacheLoader($this->root->url());
-               $configCache = new ConfigCache();
-
-               $configCacheLoader->loadConfigFiles($configCache);
-
-               $this->assertEquals('testhost', $configCache->get('database', 'hostname'));
-               $this->assertEquals('testuser', $configCache->get('database', 'username'));
-               $this->assertEquals('testpw', $configCache->get('database', 'password'));
-               $this->assertEquals('testdb', $configCache->get('database', 'database'));
-
-               $this->assertEquals('/var/run/friendica.pid', $configCache->get('system', 'pidfile'));
-               $this->assertEquals('Europe/Berlin', $configCache->get('system', 'default_timezone'));
-               $this->assertEquals('fr', $configCache->get('system', 'language'));
-       }
-
-       public function testLoadAddonConfig()
-       {
-               $structure = [
-                       'addon' => [
-                               'test' => [
-                                       'config' => [],
-                               ],
-                       ],
-               ];
-
-               vfsStream::create($structure, $this->root);
-
-               $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
-                       '..' . DIRECTORY_SEPARATOR .
-                       '..' . DIRECTORY_SEPARATOR .
-                       'datasets' . DIRECTORY_SEPARATOR .
-                       'config' . DIRECTORY_SEPARATOR .
-                       'local.config.php';
-
-               vfsStream::newFile('test.config.php')
-                       ->at($this->root->getChild('addon')->getChild('test')->getChild('config'))
-                       ->setContent(file_get_contents($file));
-
-               $configCacheLoader = new ConfigCacheLoader($this->root->url());
-
-               $conf = $configCacheLoader->loadAddonConfig('test');
-
-               $this->assertEquals('testhost', $conf['database']['hostname']);
-               $this->assertEquals('testuser', $conf['database']['username']);
-               $this->assertEquals('testpw', $conf['database']['password']);
-               $this->assertEquals('testdb', $conf['database']['database']);
-
-               $this->assertEquals('admin@test.it', $conf['config']['admin_email']);
-       }
-}
diff --git a/tests/src/Core/Config/ConfigCacheTest.php b/tests/src/Core/Config/ConfigCacheTest.php
deleted file mode 100644 (file)
index 25ea603..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-<?php
-
-namespace Friendica\Test\Core\Config;
-
-use Friendica\Core\Config\ConfigCache;
-use Friendica\Test\MockedTest;
-
-class ConfigCacheTest extends MockedTest
-{
-       public function dataTests()
-       {
-               return [
-                       'normal' => [
-                               'data' => [
-                                       'system' => [
-                                               'test' => 'it',
-                                               'boolTrue' => true,
-                                               'boolFalse' => false,
-                                               'int' => 235,
-                                               'dec' => 2.456,
-                                               'array' => ['1', 2, '3', true, false],
-                                       ],
-                                       'config' => [
-                                               'a' => 'value',
-                                       ],
-                               ]
-                       ]
-               ];
-       }
-
-       private function assertConfigValues($data, ConfigCache $configCache, $uid = null)
-       {
-               foreach ($data as $cat => $values) {
-                       foreach ($values as $key => $value) {
-                               if (isset($uid)) {
-                                       $this->assertEquals($data[$cat][$key], $configCache->getP($uid, $cat, $key));
-                               } else {
-                                       $this->assertEquals($data[$cat][$key], $configCache->get($cat, $key));
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Test the loadConfigArray() method without override
-        * @dataProvider dataTests
-        */
-       public function testLoadConfigArray($data)
-       {
-               $configCache = new ConfigCache();
-               $configCache->loadConfigArray($data);
-
-               $this->assertConfigValues($data, $configCache);
-       }
-
-       /**
-        * Test the loadConfigArray() method with overrides
-        * @dataProvider dataTests
-        */
-       public function testLoadConfigArrayOverride($data)
-       {
-               $override = [
-                       'system' => [
-                               'test' => 'not',
-                               'boolTrue' => false,
-                       ]
-               ];
-
-               $configCache = new ConfigCache();
-               $configCache->loadConfigArray($data);
-               $configCache->loadConfigArray($override);
-
-               $this->assertConfigValues($data, $configCache);
-
-               // override the value
-               $configCache->loadConfigArray($override, true);
-
-               $this->assertEquals($override['system']['test'], $configCache->get('system', 'test'));
-               $this->assertEquals($override['system']['boolTrue'], $configCache->get('system', 'boolTrue'));
-       }
-
-       /**
-        * Test the getAll() method
-        * @dataProvider dataTests
-        */
-       public function testGetAll($data)
-       {
-               $configCache = new ConfigCache();
-               $configCache->loadConfigArray($data);
-
-               $all = $configCache->getAll();
-
-               $this->assertContains($data['system'], $all);
-
-               // config values are stored directly in the array base
-               $this->assertEquals($data['config']['a'], $all['a']);
-       }
-
-       /**
-        * Test the set() and get() method
-        * @dataProvider dataTests
-        */
-       public function testSetGet($data)
-       {
-               $configCache = new ConfigCache();
-
-               foreach ($data as $cat => $values) {
-                       foreach ($values as $key => $value) {
-                               $configCache->set($cat, $key, $value);
-                       }
-               }
-
-               $this->assertConfigValues($data, $configCache);
-       }
-
-       /**
-        * Test the delete() method
-        * @dataProvider dataTests
-        */
-       public function testDelete($data)
-       {
-               $configCache = new ConfigCache($data);
-
-               foreach ($data as $cat => $values) {
-                       foreach ($values as $key => $value) {
-                               $configCache->delete($cat, $key);
-                       }
-               }
-
-               $this->assertEmpty($configCache->getAll());
-       }
-
-       /**
-        * Test the setP() and getP() methods
-        * @dataProvider dataTests
-        */
-       public function testSetGetP($data)
-       {
-               $configCache = new ConfigCache();
-               $uid = 345;
-
-               foreach ($data as $cat => $values) {
-                       foreach ($values as $key => $value) {
-                               $configCache->setP($uid, $cat, $key, $value);
-                       }
-               }
-
-               $this->assertConfigValues($data, $configCache, $uid);
-       }
-
-
-       /**
-        * Test the deleteP() method
-        * @dataProvider dataTests
-        */
-       public function testDeleteP($data)
-       {
-               $configCache = new ConfigCache();
-               $uid = 345;
-
-               foreach ($data as $cat => $values) {
-                       foreach ($values as $key => $value) {
-                               $configCache->setP($uid, $cat, $key, $value);
-                       }
-               }
-
-               foreach ($data as $cat => $values) {
-                       foreach ($values as $key => $value) {
-                               $configCache->deleteP($uid, $cat, $key);
-                       }
-               }
-
-               $this->assertEmpty($configCache->getAll());
-       }
-}
diff --git a/tests/src/Core/Config/ConfigurationTest.php b/tests/src/Core/Config/ConfigurationTest.php
new file mode 100644 (file)
index 0000000..2e4fcd4
--- /dev/null
@@ -0,0 +1,276 @@
+<?php
+
+namespace Friendica\Test\Core\Config;
+
+use Friendica\Core\Config\Adapter\IConfigAdapter;
+use Friendica\Core\Config\Cache\ConfigCache;
+use Friendica\Core\Config\Cache\IConfigCache;
+use Friendica\Core\Config\Configuration;
+use Friendica\Test\MockedTest;
+
+class ConfigurationTest extends MockedTest
+{
+       public function dataTests()
+       {
+               return [
+                       'string'       => ['data' => 'it'],
+                       'boolTrue'     => ['data' => true],
+                       'boolFalse'    => ['data' => false],
+                       'integer'      => ['data' => 235],
+                       'decimal'      => ['data' => 2.456],
+                       'array'        => ['data' => ['1', 2, '3', true, false]],
+                       'boolIntTrue'  => ['data' => 1],
+                       'boolIntFalse' => ['Data' => 0],
+               ];
+       }
+
+       /**
+        * Test the configuration initialization
+        */
+       public function testSetUp()
+       {
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(false)->once();
+
+               $configuration = new Configuration($configCache, $configAdapter);
+
+               $this->assertInstanceOf(IConfigCache::class, $configuration->getCache());
+       }
+
+       /**
+        * Test the configuration load() method
+        */
+       public function testCacheLoad()
+       {
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(true)->times(3);
+               // constructor loading
+               $configAdapter->shouldReceive('load')->andReturn([])->once();
+               // expected loading
+               $configAdapter->shouldReceive('load')->andReturn(['testing' => ['test' => 'it']])->once();
+               $configAdapter->shouldReceive('isLoaded')->with('testing', 'test')->andReturn(true)->once();
+
+               $configuration = new Configuration($configCache, $configAdapter);
+               $configuration->load('testing');
+
+               $this->assertEquals('it', $configuration->get('testing', 'test'));
+               $this->assertEquals('it', $configuration->getCache()->get('testing', 'test'));
+       }
+
+       /**
+        * Test the configuration load() method with overwrite
+        */
+       public function testCacheLoadDouble()
+       {
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(true)->times(5);
+               // constructor loading
+               $configAdapter->shouldReceive('load')->andReturn([])->once();
+               // expected loading
+               $configAdapter->shouldReceive('load')->andReturn(['testing' => ['test' => 'it']])->once();
+               $configAdapter->shouldReceive('isLoaded')->with('testing', 'test')->andReturn(true)->twice();
+               // expected next loading
+               $configAdapter->shouldReceive('load')->andReturn(['testing' => ['test' => 'again']])->once();
+
+               $configuration = new Configuration($configCache, $configAdapter);
+               $configuration->load('testing');
+
+               $this->assertEquals('it', $configuration->get('testing', 'test'));
+               $this->assertEquals('it', $configuration->getCache()->get('testing', 'test'));
+
+               $configuration->load('testing');
+
+               $this->assertEquals('again', $configuration->get('testing', 'test'));
+               $this->assertEquals('again', $configuration->getCache()->get('testing', 'test'));
+       }
+
+       /**
+        * Test the configuration get() and set() methods without adapter
+        * @dataProvider dataTests
+        */
+       public function testSetGetWithoutDB($data)
+       {
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(false)->times(3);
+
+               $configuration = new Configuration($configCache, $configAdapter);
+
+               $this->assertTrue($configuration->set('test', 'it', $data));
+
+               $this->assertEquals($data, $configuration->get('test', 'it'));
+               $this->assertEquals($data, $configuration->getCache()->get('test', 'it'));
+       }
+
+       /**
+        * Test the configuration get() and set() methods with adapter
+        * @dataProvider dataTests
+        */
+       public function testSetGetWithDB($data)
+       {
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(true)->times(3);
+               // constructor loading
+               $configAdapter->shouldReceive('load')->andReturn([])->once();
+               $configAdapter->shouldReceive('isLoaded')->with('test', 'it')->andReturn(true)->once();
+               $configAdapter->shouldReceive('set')->with('test', 'it', $data)->andReturn(true)->once();
+
+               $configuration = new Configuration($configCache, $configAdapter);
+
+               $this->assertTrue($configuration->set('test', 'it', $data));
+
+               $this->assertEquals($data, $configuration->get('test', 'it'));
+               $this->assertEquals($data, $configuration->getCache()->get('test', 'it'));
+       }
+
+       /**
+        * Test the configuration get() method with wrong value and no db
+        */
+       public function testGetWrongWithoutDB()
+       {
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(false)->times(4);
+
+               $configuration = new Configuration($configCache, $configAdapter);
+
+               // without refresh
+               $this->assertNull($configuration->get('test', 'it'));
+
+               /// beware that the cache returns '!<unset>!' and not null for a non existing value
+               $this->assertEquals('!<unset>!', $configuration->getCache()->get('test', 'it'));
+
+               // with default value
+               $this->assertEquals('default', $configuration->get('test', 'it', 'default'));
+
+               // with default value and refresh
+               $this->assertEquals('default', $configuration->get('test', 'it', 'default', true));
+       }
+
+       /**
+        * Test the configuration get() method with refresh
+        * @dataProvider dataTests
+        */
+       public function testGetWithRefresh($data)
+       {
+               $configCache = new ConfigCache(['test' => ['it' => 'now']]);
+               $configAdapter = \Mockery::mock(IConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(true)->times(4);
+               // constructor loading
+               $configAdapter->shouldReceive('load')->andReturn([])->once();
+               $configAdapter->shouldReceive('isLoaded')->with('test', 'it')->andReturn(true)->twice();
+               $configAdapter->shouldReceive('get')->with('test', 'it')->andReturn($data)->once();
+               $configAdapter->shouldReceive('isLoaded')->with('test', 'not')->andReturn(false)->once();
+               $configAdapter->shouldReceive('get')->with('test', 'not')->andReturn('!<unset>!')->once();
+
+               $configuration = new Configuration($configCache, $configAdapter);
+
+               // without refresh
+               $this->assertEquals('now', $configuration->get('test', 'it'));
+               $this->assertEquals('now', $configuration->getCache()->get('test', 'it'));
+
+               // with refresh
+               $this->assertEquals($data, $configuration->get('test', 'it', null, true));
+               $this->assertEquals($data, $configuration->getCache()->get('test', 'it'));
+
+               // without refresh and wrong value and default
+               $this->assertEquals('default', $configuration->get('test', 'not', 'default'));
+               $this->assertEquals('!<unset>!', $configuration->getCache()->get('test', 'not'));
+       }
+
+       /**
+        * Test the configuration get() method with different isLoaded settings
+        * @dataProvider dataTests
+        */
+       public function testGetWithoutLoaded($data)
+       {
+               $configCache = new ConfigCache(['test' => ['it' => 'now']]);
+               $configAdapter = \Mockery::mock(IConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(true)->times(4);
+               // constructor loading
+               $configAdapter->shouldReceive('load')->andReturn([])->once();
+
+               $configAdapter->shouldReceive('isLoaded')->with('test', 'it')->andReturn(false)->once();
+               $configAdapter->shouldReceive('get')->with('test', 'it')->andReturn('!<unset>!')->once();
+
+               $configAdapter->shouldReceive('isLoaded')->with('test', 'it')->andReturn(false)->once();
+               $configAdapter->shouldReceive('get')->with('test', 'it')->andReturn($data)->once();
+
+               $configAdapter->shouldReceive('isLoaded')->with('test', 'it')->andReturn(true)->once();
+
+               $configuration = new Configuration($configCache, $configAdapter);
+
+               // first run is not loaded and no data is found in the DB
+               $this->assertEquals('now', $configuration->get('test', 'it'));
+               $this->assertEquals('now', $configuration->getCache()->get('test', 'it'));
+
+               // second run is not loaded, but now data is found in the db (overwrote cache)
+               $this->assertEquals($data, $configuration->get('test', 'it'));
+               $this->assertEquals($data, $configuration->getCache()->get('test', 'it'));
+
+               // third run is loaded and therefore cache is used
+               $this->assertEquals($data, $configuration->get('test', 'it'));
+               $this->assertEquals($data, $configuration->getCache()->get('test', 'it'));
+       }
+
+       /**
+        * Test the configuration delete() method without adapter
+        * @dataProvider dataTests
+        */
+       public function testDeleteWithoutDB($data)
+       {
+               $configCache = new ConfigCache(['test' => ['it' => $data]]);
+               $configAdapter = \Mockery::mock(IConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(false)->times(4);
+
+               $configuration = new Configuration($configCache, $configAdapter);
+
+               $this->assertEquals($data, $configuration->get('test', 'it'));
+               $this->assertEquals($data, $configuration->getCache()->get('test', 'it'));
+
+               $this->assertTrue($configuration->delete('test', 'it'));
+               $this->assertNull($configuration->get('test', 'it'));
+               $this->assertEquals('!<unset>!', $configuration->getCache()->get('test', 'it'));
+
+               $this->assertEmpty($configuration->getCache()->getAll());
+       }
+
+       /**
+        * Test the configuration delete() method with adapter
+        */
+       public function testDeleteWithDB()
+       {
+               $configCache = new ConfigCache(['test' => ['it' => 'now', 'quarter' => 'true']]);
+               $configAdapter = \Mockery::mock(IConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(true)->times(6);
+               // constructor loading
+               $configAdapter->shouldReceive('load')->andReturn([])->once();
+               $configAdapter->shouldReceive('isLoaded')->with('test', 'it')->andReturn(true)->once();
+
+               $configAdapter->shouldReceive('delete')->with('test', 'it')->andReturn(false)->once();
+
+               $configAdapter->shouldReceive('delete')->with('test', 'second')->andReturn(true)->once();
+               $configAdapter->shouldReceive('delete')->with('test', 'third')->andReturn(false)->once();
+               $configAdapter->shouldReceive('delete')->with('test', 'quarter')->andReturn(true)->once();
+
+               $configuration = new Configuration($configCache, $configAdapter);
+
+               $this->assertEquals('now', $configuration->get('test', 'it'));
+               $this->assertEquals('now', $configuration->getCache()->get('test', 'it'));
+
+               // delete from cache only
+               $this->assertTrue($configuration->delete('test', 'it'));
+               // delete from db only
+               $this->assertTrue($configuration->delete('test', 'second'));
+               // no delete
+               $this->assertFalse($configuration->delete('test', 'third'));
+               // delete both
+               $this->assertTrue($configuration->delete('test', 'quarter'));
+
+               $this->assertEmpty($configuration->getCache()->getAll());
+       }
+}
diff --git a/tests/src/Core/Config/PConfigurationTest.php b/tests/src/Core/Config/PConfigurationTest.php
new file mode 100644 (file)
index 0000000..0259944
--- /dev/null
@@ -0,0 +1,247 @@
+<?php
+
+namespace Friendica\Test\Core\Config;
+
+use Friendica\Core\Config\Adapter\IPConfigAdapter;
+use Friendica\Core\Config\Cache\ConfigCache;
+use Friendica\Core\Config\PConfiguration;
+use Friendica\Test\MockedTest;
+
+class PConfigurationTest extends MockedTest
+{
+       public function dataTests()
+       {
+               return [
+                       'string'       => ['data' => 'it'],
+                       'boolTrue'     => ['data' => true],
+                       'boolFalse'    => ['data' => false],
+                       'integer'      => ['data' => 235],
+                       'decimal'      => ['data' => 2.456],
+                       'array'        => ['data' => ['1', 2, '3', true, false]],
+                       'boolIntTrue'  => ['data' => 1],
+                       'boolIntFalse' => ['Data' => 0],
+               ];
+       }
+
+       /**
+        * Test the configuration load() method
+        */
+       public function testCacheLoad()
+       {
+               $uid = 234;
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IPConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(true)->twice();
+               // expected loading
+               $configAdapter->shouldReceive('load')
+                       ->with($uid, 'testing')
+                       ->andReturn(['testing' => ['test' => 'it']])
+                       ->once();
+               $configAdapter->shouldReceive('isLoaded')->with($uid, 'testing', 'test')->andReturn(true)->once();
+
+               $configuration = new PConfiguration($configCache, $configAdapter);
+               $configuration->load($uid, 'testing');
+
+               $this->assertEquals('it', $configuration->get($uid, 'testing', 'test'));
+       }
+
+       /**
+        * Test the configuration load() method with overwrite
+        */
+       public function testCacheLoadDouble()
+       {
+               $uid = 234;
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IPConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(true)->times(4);
+               // expected loading
+               $configAdapter->shouldReceive('load')->with($uid, 'testing')->andReturn(['testing' => ['test' => 'it']])->once();
+               $configAdapter->shouldReceive('isLoaded')->with($uid, 'testing', 'test')->andReturn(true)->twice();
+               // expected next loading
+               $configAdapter->shouldReceive('load')->andReturn(['testing' => ['test' => 'again']])->once();
+
+               $configuration = new PConfiguration($configCache, $configAdapter);
+               $configuration->load($uid, 'testing');
+
+               $this->assertEquals('it', $configuration->get($uid, 'testing', 'test'));
+
+               $configuration->load($uid, 'testing');
+
+               $this->assertEquals('again', $configuration->get($uid, 'testing', 'test'));
+       }
+
+       /**
+        * Test the configuration get() and set() methods without adapter
+        * @dataProvider dataTests
+        */
+       public function testSetGetWithoutDB($data)
+       {
+               $uid = 234;
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IPConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(false)->times(2);
+
+               $configuration = new PConfiguration($configCache, $configAdapter);
+
+               $this->assertTrue($configuration->set($uid, 'test', 'it', $data));
+
+               $this->assertEquals($data, $configuration->get($uid, 'test', 'it'));
+       }
+
+       /**
+        * Test the configuration get() and set() methods with adapter
+        * @dataProvider dataTests
+        */
+       public function testSetGetWithDB($data)
+       {
+               $uid = 234;
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IPConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(true)->times(2);
+               $configAdapter->shouldReceive('isLoaded')->with($uid, 'test', 'it')->andReturn(true)->once();
+               $configAdapter->shouldReceive('set')->with($uid, 'test', 'it', $data)->andReturn(true)->once();
+
+               $configuration = new PConfiguration($configCache, $configAdapter);
+
+               $this->assertTrue($configuration->set($uid, 'test', 'it', $data));
+
+               $this->assertEquals($data, $configuration->get($uid, 'test', 'it'));
+       }
+
+       /**
+        * Test the configuration get() method with wrong value and no db
+        */
+       public function testGetWrongWithoutDB()
+       {
+               $uid = 234;
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IPConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(false)->times(3);
+
+               $configuration = new PConfiguration($configCache, $configAdapter);
+
+               // without refresh
+               $this->assertNull($configuration->get($uid, 'test', 'it'));
+
+               // with default value
+               $this->assertEquals('default', $configuration->get($uid, 'test', 'it', 'default'));
+
+               // with default value and refresh
+               $this->assertEquals('default', $configuration->get($uid, 'test', 'it', 'default', true));
+       }
+
+       /**
+        * Test the configuration get() method with refresh
+        * @dataProvider dataTests
+        */
+       public function testGetWithRefresh($data)
+       {
+               $uid = 234;
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IPConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(true)->times(4);
+               $configAdapter->shouldReceive('isLoaded')->with($uid, 'test', 'it')->andReturn(false)->once();
+               $configAdapter->shouldReceive('get')->with($uid, 'test', 'it')->andReturn('now')->once();
+               $configAdapter->shouldReceive('isLoaded')->with($uid, 'test', 'it')->andReturn(true)->twice();
+               $configAdapter->shouldReceive('get')->with($uid, 'test', 'it')->andReturn($data)->once();
+               $configAdapter->shouldReceive('isLoaded')->with($uid, 'test', 'not')->andReturn(false)->once();
+               $configAdapter->shouldReceive('get')->with($uid, 'test', 'not')->andReturn('!<unset>!')->once();
+
+               $configuration = new PConfiguration($configCache, $configAdapter);
+
+               // without refresh
+               $this->assertEquals('now', $configuration->get($uid, 'test', 'it'));
+               // use the cache again
+               $this->assertEquals('now', $configuration->get($uid, 'test', 'it'));
+
+               // with refresh (and load the second value out of the db)
+               $this->assertEquals($data, $configuration->get($uid, 'test', 'it', null, true));
+
+               // without refresh and wrong value and default
+               $this->assertEquals('default', $configuration->get($uid, 'test', 'not', 'default'));
+       }
+
+       /**
+        * Test the configuration get() method with different isLoaded settings
+        * @dataProvider dataTests
+        */
+       public function testGetWithoutLoaded($data)
+       {
+               $uid = 234;
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IPConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(true)->times(3);
+
+               $configAdapter->shouldReceive('isLoaded')->with($uid, 'test', 'it')->andReturn(false)->once();
+               $configAdapter->shouldReceive('get')->with($uid, 'test', 'it')->andReturn('!<unset>!')->once();
+
+               $configAdapter->shouldReceive('isLoaded')->with($uid, 'test', 'it')->andReturn(false)->once();
+               $configAdapter->shouldReceive('get')->with($uid, 'test', 'it')->andReturn($data)->once();
+
+               $configAdapter->shouldReceive('isLoaded')->with($uid, 'test', 'it')->andReturn(true)->once();
+
+               $configuration = new PConfiguration($configCache, $configAdapter);
+
+               // first run is not loaded and no data is found in the DB
+               $this->assertNull($configuration->get($uid, 'test', 'it'));
+
+               // second run is not loaded, but now data is found in the db (overwrote cache)
+               $this->assertEquals($data, $configuration->get($uid,'test', 'it'));
+
+               // third run is loaded and therefore cache is used
+               $this->assertEquals($data, $configuration->get($uid,'test', 'it'));
+       }
+
+       /**
+        * Test the configuration delete() method without adapter
+        * @dataProvider dataTests
+        */
+       public function testDeleteWithoutDB($data)
+       {
+               $uid = 234;
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IPConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(false)->times(4);
+
+               $configuration = new PConfiguration($configCache, $configAdapter);
+
+               $this->assertTrue($configuration->set($uid, 'test', 'it', $data));
+               $this->assertEquals($data, $configuration->get($uid, 'test', 'it'));
+
+               $this->assertTrue($configuration->delete($uid, 'test', 'it'));
+               $this->assertNull($configuration->get($uid, 'test', 'it'));
+       }
+
+       /**
+        * Test the configuration delete() method with adapter
+        */
+       public function testDeleteWithDB()
+       {
+               $uid = 234;
+               $configCache = new ConfigCache();
+               $configAdapter = \Mockery::mock(IPConfigAdapter::class);
+               $configAdapter->shouldReceive('isConnected')->andReturn(true)->times(6);
+               $configAdapter->shouldReceive('set')->with($uid, 'test', 'it', 'now')->andReturn(false)->once();
+               $configAdapter->shouldReceive('isLoaded')->with($uid, 'test', 'it')->andReturn(true)->once();
+
+               $configAdapter->shouldReceive('delete')->with($uid, 'test', 'it')->andReturn(false)->once();
+
+               $configAdapter->shouldReceive('delete')->with($uid, 'test', 'second')->andReturn(true)->once();
+               $configAdapter->shouldReceive('delete')->with($uid, 'test', 'third')->andReturn(false)->once();
+               $configAdapter->shouldReceive('delete')->with($uid, 'test', 'quarter')->andReturn(true)->once();
+
+               $configuration = new PConfiguration($configCache, $configAdapter);
+
+               $this->assertFalse($configuration->set($uid, 'test', 'it', 'now'));
+               $this->assertEquals('now', $configuration->get($uid, 'test', 'it'));
+
+               // delete from set
+               $this->assertTrue($configuration->delete($uid, 'test', 'it'));
+               // delete from db only
+               $this->assertTrue($configuration->delete($uid, 'test', 'second'));
+               // no delete
+               $this->assertFalse($configuration->delete($uid, 'test', 'third'));
+               // delete both
+               $this->assertTrue($configuration->delete($uid, 'test', 'quarter'));
+       }
+}
index 41ccce0b28827410ebe67a6695d9788032af77b1..73b6835fb5cce41a46731c4a800079a978beab1d 100644 (file)
@@ -52,9 +52,9 @@ class AutomaticInstallationConsoleTest extends ConsoleTest
                $this->db_user = getenv('MYSQL_USERNAME') . getenv('MYSQL_USER');
                $this->db_pass = getenv('MYSQL_PASSWORD');
 
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('config', 'php_path', NULL)
+                       ->with('config', 'php_path')
                        ->andReturn(false);
 
                $this->mockL10nT();
index 505c4f794dc58db64f1299d673798e2cb7c14a70..579b28e026b4a94ff1623c5e4710a65472d27c00 100644 (file)
@@ -32,14 +32,14 @@ class ConfigConsoleTest extends ConsoleTest
        }
 
        function testSetGetKeyValue() {
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('set')
                        ->with('config', 'test', 'now')
                        ->andReturn(true)
                        ->once();
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('config', 'test', NULL)
+                       ->with('config', 'test')
                        ->andReturn('now')
                        ->twice();
 
@@ -50,9 +50,9 @@ class ConfigConsoleTest extends ConsoleTest
                $txt = $this->dumpExecute($console);
                $this->assertEquals("config.test <= now\n", $txt);
 
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('config', 'test', null)
+                       ->with('config', 'test')
                        ->andReturn('now')
                        ->once();
 
@@ -62,9 +62,9 @@ class ConfigConsoleTest extends ConsoleTest
                $txt = $this->dumpExecute($console);
                $this->assertEquals("config.test => now\n", $txt);
 
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('config', 'test', null)
+                       ->with('config', 'test')
                        ->andReturn(null)
                        ->once();
 
@@ -77,9 +77,9 @@ class ConfigConsoleTest extends ConsoleTest
 
        function testSetArrayValue() {
                $testArray = [1, 2, 3];
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('config', 'test', null)
+                       ->with('config', 'test')
                        ->andReturn($testArray)
                        ->once();
 
@@ -105,9 +105,9 @@ class ConfigConsoleTest extends ConsoleTest
        }
 
        function testVerbose() {
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('test', 'it', null)
+                       ->with('test', 'it')
                        ->andReturn('now')
                        ->once();
                $console = new Config($this->consoleArgv);
@@ -133,14 +133,14 @@ CONF;
        }
 
        function testUnableToSet() {
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('set')
                        ->with('test', 'it', 'now')
                        ->andReturn(false)
                        ->once();
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('test', 'it', NULL)
+                       ->with('test', 'it')
                        ->andReturn(NULL)
                        ->once();
                $console = new Config();
index 905d214cac2b6282ceb298c5c5a391d3073d0587..4f7acc9c4229f62223b42cbdfca7121e46bffc81 100644 (file)
@@ -29,8 +29,7 @@ abstract class ConsoleTest extends MockedTest
                Intercept::setUp();
 
                $this->setUpVfsDir();
-               $configMock = \Mockery::mock('Friendica\Core\Config\ConfigCache');
-               $this->mockApp($this->root, $configMock);
+               $this->mockApp($this->root);
        }
 
        /**
index ab8e1b2f2efc1f60171c22b021b908e4f33bcde4..6dc170e51429bdfc659e8979b5e36cdc0e239d86 100644 (file)
@@ -27,8 +27,7 @@ abstract class LockTest extends MockedTest
        {
                // Reusable App object
                $this->setUpVfsDir();
-               $configMock = \Mockery::mock('Friendica\Core\Config\ConfigCache');
-               $this->mockApp($this->root, $configMock);
+               $this->mockApp($this->root);
                $this->app
                        ->shouldReceive('getHostname')
                        ->andReturn('friendica.local');
index 46f29f52e2f9da8a758f2d3a68e9e063bfa390d6..ad20f5bfdb79dbe31ee29ed282b8836af0084f14 100644 (file)
@@ -13,14 +13,14 @@ class MemcacheCacheLockDriverTest extends LockTest
 {
        protected function getInstance()
        {
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('system', 'memcache_host', NULL)
+                       ->with('system', 'memcache_host')
                        ->andReturn('localhost');
 
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('system', 'memcache_port', NULL)
+                       ->with('system', 'memcache_port')
                        ->andReturn(11211);
 
                return new CacheLockDriver(CacheDriverFactory::create('memcache'));
index 72271c98b9ef98d2c87dd72998e0e687e39156bf..a5bdeaedb8a940492420ae8066b52f4bea062a43 100644 (file)
@@ -13,9 +13,9 @@ class MemcachedCacheLockDriverTest extends LockTest
 {
        protected function getInstance()
        {
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('system', 'memcached_hosts', NULL)
+                       ->with('system', 'memcached_hosts')
                        ->andReturn([0 => 'localhost, 11211']);
 
                return new CacheLockDriver(CacheDriverFactory::create('memcached'));
index 0c9deea16e3ba9124d43e526f4fa0d7f8e53a3fd..5f047bc66418124e5005bb0560a25311d62f8f18 100644 (file)
@@ -13,14 +13,14 @@ class RedisCacheLockDriverTest extends LockTest
 {
        protected function getInstance()
        {
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('system', 'redis_host', NULL)
+                       ->with('system', 'redis_host')
                        ->andReturn('localhost');
 
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('system', 'redis_port', NULL)
+                       ->with('system', 'redis_port')
                        ->andReturn(null);
 
                return new CacheLockDriver(CacheDriverFactory::create('redis'));
index c2b94145725187d7e951d644903b15e4cdf06f3f..a37fbffbed24c86a7076fd060216e50b751a84cd 100644 (file)
@@ -12,9 +12,9 @@ class SemaphoreLockDriverTest extends LockTest
 
                $this->app->shouldReceive('getHostname')->andReturn('friendica.local');
 
-               $this->configCache
+               $this->configMock
                        ->shouldReceive('get')
-                       ->with('system', 'temppath', NULL)
+                       ->with('system', 'temppath')
                        ->andReturn('/tmp/');
        }
 
index f2a5cc5558f7dcd853a377d2065f905fbe245331..e8b9c68b19c3aff0f40e9457c923931ab4bf4e4a 100644 (file)
@@ -3,6 +3,7 @@ namespace Friendica\Test\Database;
 
 use Friendica\App;
 use Friendica\Core\Config;
+use Friendica\Core\Config\Cache;
 use Friendica\Database\DBA;
 use Friendica\Factory;
 use Friendica\Test\DatabaseTest;
@@ -13,11 +14,14 @@ class DBATest extends DatabaseTest
        public function setUp()
        {
                $basedir = BasePath::create(dirname(__DIR__) . '/../../');
-               $configLoader = new Config\ConfigCacheLoader($basedir);
-               $config = Factory\ConfigFactory::createCache($configLoader);
+               $configLoader = new Cache\ConfigCacheLoader($basedir);
+               $configCache = Factory\ConfigFactory::createCache($configLoader);
+               $profiler = Factory\ProfilerFactory::create($configCache);
+               Factory\DBFactory::init($configCache, $profiler, $_SERVER);
+               $config = Factory\ConfigFactory::createConfig($configCache);
+               Factory\ConfigFactory::createPConfig($configCache);
                $logger = Factory\LoggerFactory::create('test', $config);
-               $this->app = new App($config, $logger, false);
-               $this->logOutput = FActory\LoggerFactory::enableTest($this->app->getLogger());
+               $this->app = new App($config, $logger, $profiler, false);
 
                parent::setUp();
 
index bc50a0a691aa43cb4cf2121196767be1aa403f60..325ad4e5e7f18571358e7403473b265c0d437129 100644 (file)
@@ -3,7 +3,7 @@
 namespace Friendica\Test\Database;
 
 use Friendica\App;
-use Friendica\Core\Config;
+use Friendica\Core\Config\Cache;
 use Friendica\Database\DBStructure;
 use Friendica\Factory;
 use Friendica\Test\DatabaseTest;
@@ -14,11 +14,14 @@ class DBStructureTest extends DatabaseTest
        public function setUp()
        {
                $basedir = BasePath::create(dirname(__DIR__) . '/../../');
-               $configLoader = new Config\ConfigCacheLoader($basedir);
-               $config = Factory\ConfigFactory::createCache($configLoader);
+               $configLoader = new Cache\ConfigCacheLoader($basedir);
+               $configCache = Factory\ConfigFactory::createCache($configLoader);
+               $profiler = Factory\ProfilerFactory::create($configCache);
+               Factory\DBFactory::init($configCache, $profiler, $_SERVER);
+               $config = Factory\ConfigFactory::createConfig($configCache);
+               Factory\ConfigFactory::createPConfig($configCache);
                $logger = Factory\LoggerFactory::create('test', $config);
-               $this->app = new App($config, $logger, false);
-               $this->logOutput = FActory\LoggerFactory::enableTest($this->app->getLogger());
+               $this->app = new App($config, $logger, $profiler, false);
 
                parent::setUp();
        }
diff --git a/tests/src/Util/ProfilerTest.php b/tests/src/Util/ProfilerTest.php
new file mode 100644 (file)
index 0000000..f242fd4
--- /dev/null
@@ -0,0 +1,181 @@
+<?php
+
+namespace src\Util;
+
+use Friendica\Test\MockedTest;
+use Friendica\Util\Profiler;
+use Mockery\MockInterface;
+use Psr\Log\LoggerInterface;
+
+class ProfilerTest extends MockedTest
+{
+       /**
+        * @var LoggerInterface|MockInterface
+        */
+       private $logger;
+
+       protected function setUp()
+       {
+               parent::setUp();
+
+               $this->logger = \Mockery::mock('Psr\Log\LoggerInterface');
+       }
+
+       /**
+        * Test the Profiler setup
+        */
+       public function testSetUp()
+       {
+               $profiler = new Profiler(true, true);
+       }
+
+       /**
+        * A dataset for different profiling settings
+        * @return array
+        */
+       public function dataPerformance()
+       {
+               return [
+                       'database' => [
+                               'timestamp' => time(),
+                               'name' => 'database',
+                               'functions' => ['test', 'it'],
+                       ],
+                       'database_write' => [
+                               'timestamp' => time(),
+                               'name' => 'database_write',
+                               'functions' => ['test', 'it2'],
+                       ],
+                       'cache' => [
+                               'timestamp' => time(),
+                               'name' => 'cache',
+                               'functions' => ['test', 'it3'],
+                       ],
+                       'cache_write' => [
+                               'timestamp' => time(),
+                               'name' => 'cache_write',
+                               'functions' => ['test', 'it4'],
+                       ],
+                       'network' => [
+                               'timestamp' => time(),
+                               'name' => 'network',
+                               'functions' => ['test', 'it5'],
+                       ],
+                       'file' => [
+                               'timestamp' => time(),
+                               'name' => 'file',
+                               'functions' => [],
+                       ],
+                       'rendering' => [
+                               'timestamp' => time(),
+                               'name' => 'rendering',
+                               'functions' => ['test', 'it7'],
+                       ],
+                       'parser' => [
+                               'timestamp' => time(),
+                               'name' => 'parser',
+                               'functions' => ['test', 'it8'],
+                       ],
+                       'marktime' => [
+                               'timestamp' => time(),
+                               'name' => 'parser',
+                               'functions' => ['test'],
+                       ],
+                       // This one isn't set during reset
+                       'unknown' => [
+                               'timestamp' => time(),
+                               'name' => 'unknown',
+                               'functions' => ['test'],
+                       ],
+               ];
+       }
+
+       /**
+        * Test the Profiler savetimestamp
+        * @dataProvider dataPerformance
+        */
+       public function testSaveTimestamp($timestamp, $name, array $functions)
+       {
+               $profiler = new Profiler(true, true);
+
+               foreach ($functions as $function) {
+                       $profiler->saveTimestamp($timestamp, $name, $function);
+               }
+
+               $this->assertGreaterThanOrEqual(0, $profiler->get($name));
+       }
+
+       /**
+        * Test the Profiler reset
+        * @dataProvider dataPerformance
+        */
+       public function testReset($timestamp, $name, array $functions)
+       {
+               $profiler = new Profiler(true, true);
+
+               $profiler->saveTimestamp($timestamp, $name);
+               $profiler->reset();
+
+               $this->assertEquals(0, $profiler->get($name));
+       }
+
+       public function dataBig()
+       {
+               return [
+                       'big' => [
+                               'data' => [
+                                       'database' => [
+                                               'timestamp' => time(),
+                                               'name' => 'database',
+                                               'functions' => ['test', 'it'],
+                                       ],
+                                       'database_write' => [
+                                               'timestamp' => time(),
+                                               'name' => 'database_write',
+                                               'functions' => ['test', 'it2'],
+                                       ],
+                                       'cache' => [
+                                               'timestamp' => time(),
+                                               'name' => 'cache',
+                                               'functions' => ['test', 'it3'],
+                                       ],
+                                       'cache_write' => [
+                                               'timestamp' => time(),
+                                               'name' => 'cache_write',
+                                               'functions' => ['test', 'it4'],
+                                       ],
+                                       'network' => [
+                                               'timestamp' => time(),
+                                               'name' => 'network',
+                                               'functions' => ['test', 'it5'],
+                                       ],
+                               ]
+                       ]
+               ];
+       }
+
+       /**
+        * Test the output of the Profiler
+        * @dataProvider dataBig
+        */
+       public function testSaveLog($data)
+       {
+               $this->logger
+                       ->shouldReceive('info')
+                       ->with('test', \Mockery::any())
+                       ->once();
+               $this->logger
+                       ->shouldReceive('info')
+                       ->once();
+
+               $profiler = new Profiler(true, true);
+
+               foreach ($data as $perf => $items) {
+                       foreach ($items['functions'] as $function) {
+                               $profiler->saveTimestamp($items['timestamp'], $items['name'], $function);
+                       }
+               }
+
+               $profiler->saveLog($this->logger, 'test');
+       }
+}