*/
use Friendica\App;
+use Friendica\Core\Config;
+use Friendica\Factory;
+use Friendica\Util\BasePath;
use Friendica\Util\ExAuth;
-use Friendica\Util\LoggerFactory;
if (sizeof($_SERVER["argv"]) == 0) {
die();
require dirname(__DIR__) . '/vendor/autoload.php';
-$logger = LoggerFactory::create('auth_ejabberd');
+$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(dirname(__DIR__), $logger);
+$a = new App($config, $logger);
if ($a->getMode()->isNormal()) {
$oAuth = new ExAuth();
require dirname(__DIR__) . '/vendor/autoload.php';
-use Friendica\Util\LoggerFactory;
+use Friendica\Core\Config;
+use Friendica\Factory;
+use Friendica\Util\BasePath;
-$logger = LoggerFactory::create('console');
+$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(dirname(__DIR__), $logger);
+$a = new Friendica\App($config, $logger);
\Friendica\BaseObject::setApp($a);
(new Friendica\Core\Console($argv))->execute();
use Friendica\Core\Config;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
-use Friendica\Util\LoggerFactory;
+use Friendica\Factory;
+use Friendica\Util\BasePath;
// Get options
$shortopts = 'f';
require dirname(__DIR__) . '/vendor/autoload.php';
-$logger = LoggerFactory::create('daemon');
+$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(dirname(__DIR__), $logger);
+$a = new App($config, $logger);
if ($a->getMode()->isInstall()) {
die("Friendica isn't properly installed yet.\n");
* @file bin/worker.php
* @brief Starts the background processing
*/
+
use Friendica\App;
use Friendica\Core\Config;
-use Friendica\Core\Worker;
use Friendica\Core\Update;
-use Friendica\Util\LoggerFactory;
+use Friendica\Core\Worker;
+use Friendica\Factory;
+use Friendica\Util\BasePath;
// Get options
$shortopts = 'sn';
require dirname(__DIR__) . '/vendor/autoload.php';
-$logger = LoggerFactory::create('worker');
+$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(dirname(__DIR__), $logger);
+$a = new App($config, $logger);
// Check the database structure and possibly fixes it
-Update::check(true);
+Update::check($a->getBasePath(), true);
// Quit when in maintenance
if (!$a->getMode()->has(App\Mode::MAINTENANCEDISABLED)) {
use Friendica\App;
use Friendica\BaseObject;
-use Friendica\Core\Addon;
-use Friendica\Core\Cache;
use Friendica\Core\Config;
-use Friendica\Core\L10n;
use Friendica\Core\PConfig;
use Friendica\Core\Protocol;
use Friendica\Core\System;
-use Friendica\Core\Update;
-use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
-use Friendica\Model\Conversation;
+use Friendica\Util\BasePath;
use Friendica\Util\DateTimeFormat;
define('FRIENDICA_PLATFORM', 'Friendica');
$temppath = Config::get("system", "temppath");
- if (($temppath != "") && App::isDirectoryUsable($temppath)) {
+ if (($temppath != "") && System::isDirectoryUsable($temppath)) {
// We have a temp path and it is usable
- return App::getRealPath($temppath);
+ return BasePath::getRealPath($temppath);
}
// We don't have a working preconfigured temp path, so we take the system path.
$temppath = sys_get_temp_dir();
// Check if it is usable
- if (($temppath != "") && App::isDirectoryUsable($temppath)) {
+ if (($temppath != "") && System::isDirectoryUsable($temppath)) {
// Always store the real path, not the path through symlinks
- $temppath = App::getRealPath($temppath);
+ $temppath = BasePath::getRealPath($temppath);
// To avoid any interferences with other systems we create our own directory
$new_temppath = $temppath . "/" . $a->getHostName();
mkdir($new_temppath);
}
- if (App::isDirectoryUsable($new_temppath)) {
+ if (System::isDirectoryUsable($new_temppath)) {
// The new path is usable, we are happy
Config::set("system", "temppath", $new_temppath);
return $new_temppath;
}
$itemcache = Config::get('system', 'itemcache');
- if (($itemcache != "") && App::isDirectoryUsable($itemcache)) {
- return App::getRealPath($itemcache);
+ if (($itemcache != "") && System::isDirectoryUsable($itemcache)) {
+ return BasePath::getRealPath($itemcache);
}
$temppath = get_temppath();
mkdir($itemcache);
}
- if (App::isDirectoryUsable($itemcache)) {
+ if (System::isDirectoryUsable($itemcache)) {
Config::set("system", "itemcache", $itemcache);
return $itemcache;
}
function get_spoolpath()
{
$spoolpath = Config::get('system', 'spoolpath');
- if (($spoolpath != "") && App::isDirectoryUsable($spoolpath)) {
+ if (($spoolpath != "") && System::isDirectoryUsable($spoolpath)) {
// We have a spool path and it is usable
return $spoolpath;
}
mkdir($spoolpath);
}
- if (App::isDirectoryUsable($spoolpath)) {
+ if (System::isDirectoryUsable($spoolpath)) {
// The new path is usable, we are happy
Config::set("system", "spoolpath", $spoolpath);
return $spoolpath;
use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) {
- define('DB_UPDATE_VERSION', 1300);
+ define('DB_UPDATE_VERSION', 1301);
}
return [
],
"indexes" => [
"PRIMARY" => ["id"],
- "pid" => ["pid"],
- "parameter" => ["parameter(64)"],
- "priority_created_next_try" => ["priority", "created", "next_try"],
+ "done_parameter" => ["done", "parameter(64)"],
+ "done_pid" => ["done", "pid"],
+ "done_priority_created_next_try" => ["done", "priority", "created", "next_try"],
"done_priority_executed_next_try" => ["done", "priority", "executed", "next_try"],
- "done_executed_next_try" => ["done", "executed", "next_try"],
"done_priority_next_try" => ["done", "priority", "next_try"],
+ "done_executed_next_try" => ["done", "executed", "next_try"],
"done_next_try" => ["done", "next_try"]
]
],
*/
use Friendica\App;
-use Friendica\Util\LoggerFactory;
+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.');
require __DIR__ . '/vendor/autoload.php';
-$logger = LoggerFactory::create('index');
+$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(__DIR__, $logger, false);
+$a = new App($config, $logger, false);
$a->runFrontend();
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
+use Friendica\Core\StorageManager;
use Friendica\Core\System;
use Friendica\Core\Theme;
use Friendica\Core\Update;
use Friendica\Core\Worker;
-use Friendica\Core\StorageManager;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\Model\Contact;
use Friendica\Module\Login;
use Friendica\Module\Tos;
use Friendica\Util\Arrays;
+use Friendica\Util\BasePath;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Network;
use Friendica\Util\Strings;
}
if (Config::get('system', 'dbupdate', DBStructure::UPDATE_NOT_CHECKED) == DBStructure::UPDATE_NOT_CHECKED) {
- DBStructure::update(false, true);
+ DBStructure::update($a->getBasePath(), false, true);
}
if (Config::get('system', 'dbupdate') == DBStructure::UPDATE_FAILED) {
$showwarning = true;
Config::set('system', 'dbclean-expire-unclaimed', $dbclean_unclaimed);
if ($itemcache != '') {
- $itemcache = App::getRealPath($itemcache);
+ $itemcache = BasePath::getRealPath($itemcache);
}
Config::set('system', 'itemcache', $itemcache);
Config::set('system', 'max_comments', $max_comments);
if ($temppath != '') {
- $temppath = App::getRealPath($temppath);
+ $temppath = BasePath::getRealPath($temppath);
}
Config::set('system', 'temppath', $temppath);
if ($basepath != '') {
- $basepath = App::getRealPath($basepath);
+ $basepath = BasePath::getRealPath($basepath);
}
Config::set('system', 'basepath' , $basepath);
'$hide_help' => ['hide_help', L10n::t("Hide help entry from navigation menu"), Config::get('system', 'hide_help'), L10n::t("Hides the menu entry for the Help pages from the navigation menu. You can still access it calling /help directly.")],
'$singleuser' => ['singleuser', L10n::t("Single user instance"), Config::get('system', 'singleuser', '---'), L10n::t("Make this instance multi-user or single-user for the named user"), $user_names],
- '$storagebackend' => ['storagebackend', L10n::t("File storage backend"), $storage_current_backend, L10n::t('The backend used to store uploaded files data. If you change the storage backend, you have to manually move the existing files see <a href="/help/Settings#1_2_3_1">the settings documentation</a> for more information about the choices and the moving procedure.'), $storage_backends_choices],
+ '$storagebackend' => ['storagebackend', L10n::t("File storage backend"), $storage_current_backend, L10n::t('The backend used to store uploaded data. If you change the storage backend, you can manually move the existing files. If you do not do so, the files uploaded before the change will still be available at the old backend. Please see <a href="/help/Settings#1_2_3_1">the settings documentation</a> for more information about the choices and the moving procedure.'), $storage_backends_choices],
'$storageform' => $storage_form,
'$maximagesize' => ['maximagesize', L10n::t("Maximum image size"), Config::get('system', 'maximagesize'), L10n::t("Maximum size in bytes of uploaded images. Default is 0, which means no limits.")],
'$maximagelength' => ['maximagelength', L10n::t("Maximum image length"), Config::get('system', 'max_image_length'), L10n::t("Maximum length in pixels of the longest side of uploaded images. Default is -1, which means no limits.")],
}
if (($a->argc > 2) && (intval($a->argv[2]) || ($a->argv[2] === 'check'))) {
- $retval = DBStructure::update(false, true);
+ $retval = DBStructure::update($a->getBasePath(), false, true);
if ($retval === '') {
$o .= L10n::t("Database structure update %s was successfully applied.", DB_UPDATE_VERSION) . "<br />";
Config::set('database', 'last_successful_update', DB_UPDATE_VERSION);
}
$sql_extra = '';
- if (!empty($a->config['admin_nickname'])) {
+ if (Config::get('config', 'admin_nickname') !== null) {
$sql_extra = sprintf(" AND `nickname` = '%s' ", DBA::escape(Config::get('config', 'admin_nickname')));
}
if (!empty(Config::get('config', 'admin_email'))) {
Config::load('feature_lock');
$locked_features = [];
- if (!empty($a->config['feature_lock'])) {
- foreach ($a->config['feature_lock'] as $k => $v) {
+ $featureLock = Config::get('config', 'feature_lock');
+ if (isset($featureLock)) {
+ foreach ($featureLock as $k => $v) {
if ($k === 'config_loaded') {
continue;
}
use DOMDocument;
use DOMXPath;
use Exception;
+use Friendica\Core\Config\ConfigCache;
+use Friendica\Core\Config\ConfigCacheLoader;
use Friendica\Database\DBA;
+use Friendica\Factory\ConfigFactory;
use Friendica\Network\HTTPException\InternalServerErrorException;
use Psr\Log\LoggerInterface;
public $module_loaded = false;
public $module_class = null;
public $query_string = '';
- public $config = [];
public $page = [];
public $profile;
public $profile_uid;
*/
private $logger;
+ /**
+ * @var ConfigCache The cached config
+ */
+ private $config;
+
+ /**
+ * Returns the current config cache of this node
+ *
+ * @return ConfigCache
+ */
+ public function getConfig()
+ {
+ return $this->config;
+ }
+
+ /**
+ * The basepath of this app
+ *
+ * @return string
+ */
+ public function getBasePath()
+ {
+ return $this->basePath;
+ }
+
/**
* Register a stylesheet file path to be included in the <head> tag of every page.
* Inclusion is done in App->initHead().
*/
public function registerStylesheet($path)
{
- $url = str_replace($this->getBasePath() . DIRECTORY_SEPARATOR, '', $path);
+ $url = str_replace($this->basePath . DIRECTORY_SEPARATOR, '', $path);
$this->stylesheets[] = trim($url, '/');
}
*/
public function registerFooterScript($path)
{
- $url = str_replace($this->getBasePath() . DIRECTORY_SEPARATOR, '', $path);
+ $url = str_replace($this->basePath . DIRECTORY_SEPARATOR, '', $path);
$this->footerScripts[] = trim($url, '/');
}
/**
* @brief App constructor.
*
- * @param string $basePath Path to the app base folder
+ * @param ConfigCache $config The Cached Config
* @param LoggerInterface $logger Logger 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($basePath, LoggerInterface $logger, $isBackend = true)
+ public function __construct(ConfigCache $config, LoggerInterface $logger, $isBackend = true)
{
- $this->logger = $logger;
+ $this->config = $config;
+ $this->logger = $logger;
+ $this->basePath = $this->config->get('system', 'basepath');
- if (!static::isDirectoryUsable($basePath, false)) {
- throw new Exception('Basepath ' . $basePath . ' isn\'t usable.');
+ if (!Core\System::isDirectoryUsable($this->basePath, false)) {
+ throw new Exception('Basepath ' . $this->basePath . ' isn\'t usable.');
}
+ $this->basePath = rtrim($this->basePath, DIRECTORY_SEPARATOR);
BaseObject::setApp($this);
- $this->basePath = rtrim($basePath, DIRECTORY_SEPARATOR);
$this->checkBackend($isBackend);
$this->checkFriendicaApp();
$this->callstack['rendering'] = [];
$this->callstack['parser'] = [];
- $this->mode = new App\Mode($basePath);
+ $this->mode = new App\Mode($this->basePath);
$this->reload();
set_include_path(
get_include_path() . PATH_SEPARATOR
- . $this->getBasePath() . DIRECTORY_SEPARATOR . 'include' . PATH_SEPARATOR
- . $this->getBasePath() . DIRECTORY_SEPARATOR . 'library' . PATH_SEPARATOR
- . $this->getBasePath());
+ . $this->basePath . DIRECTORY_SEPARATOR . 'include' . PATH_SEPARATOR
+ . $this->basePath . DIRECTORY_SEPARATOR . 'library' . PATH_SEPARATOR
+ . $this->basePath);
if (!empty($_SERVER['QUERY_STRING']) && strpos($_SERVER['QUERY_STRING'], 'pagename=') === 0) {
$this->query_string = substr($_SERVER['QUERY_STRING'], 9);
*/
public function reload()
{
- // The order of the following calls is important to ensure proper initialization
- $this->loadConfigFiles();
+ Core\Config::init($this->config);
+ Core\PConfig::init($this->config);
$this->loadDatabase();
- $this->getMode()->determine($this->getBasePath());
+ $this->getMode()->determine($this->basePath);
$this->determineURLPath();
- Core\Config::load();
+ 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();
-
- $this->loadAddonConfig();
+ $loader = new ConfigCacheLoader($this->basePath);
+ Core\Hook::callAll('load_config', $loader);
+ $this->config->loadConfigArray($loader->loadCoreConfig('addon'), true);
}
$this->loadDefaultTimezone();
Core\Logger::setLogger($this->logger);
}
- /**
- * 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
- */
- private function loadConfigFiles()
- {
- $this->loadConfigFile($this->getBasePath() . '/config/defaults.config.php');
- $this->loadConfigFile($this->getBasePath() . '/config/settings.config.php');
-
- // Legacy .htconfig.php support
- if (file_exists($this->getBasePath() . '/.htpreconfig.php')) {
- $a = $this;
- include $this->getBasePath() . '/.htpreconfig.php';
- }
-
- // Legacy .htconfig.php support
- if (file_exists($this->getBasePath() . '/.htconfig.php')) {
- $a = $this;
-
- include $this->getBasePath() . '/.htconfig.php';
-
- $this->setConfigValue('database', 'hostname', $db_host);
- $this->setConfigValue('database', 'username', $db_user);
- $this->setConfigValue('database', 'password', $db_pass);
- $this->setConfigValue('database', 'database', $db_data);
- if (isset($a->config['system']['db_charset'])) {
- $this->setConfigValue('database', 'charset', $a->config['system']['db_charset']);
- }
-
- unset($db_host, $db_user, $db_pass, $db_data);
-
- if (isset($default_timezone)) {
- $this->setConfigValue('system', 'default_timezone', $default_timezone);
- unset($default_timezone);
- }
-
- if (isset($pidfile)) {
- $this->setConfigValue('system', 'pidfile', $pidfile);
- unset($pidfile);
- }
-
- if (isset($lang)) {
- $this->setConfigValue('system', 'language', $lang);
- unset($lang);
- }
- }
-
- if (file_exists($this->getBasePath() . '/config/local.config.php')) {
- $this->loadConfigFile($this->getBasePath() . '/config/local.config.php', true);
- } elseif (file_exists($this->getBasePath() . '/config/local.ini.php')) {
- $this->loadINIConfigFile($this->getBasePath() . '/config/local.ini.php', true);
- }
- }
-
- /**
- * Tries to load the specified legacy configuration file into the App->config array.
- * Doesn't overwrite previously set values by default to prevent default config files to supersede DB Config.
- *
- * @deprecated since version 2018.12
- * @param string $filepath
- * @param bool $overwrite Force value overwrite if the config key already exists
- * @throws Exception
- */
- public function loadINIConfigFile($filepath, $overwrite = false)
- {
- if (!file_exists($filepath)) {
- throw new Exception('Error parsing non-existent INI config file ' . $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);
- }
-
- $this->loadConfigArray($config, $overwrite);
- }
-
- /**
- * Tries to load the specified configuration file into the App->config array.
- * Doesn't overwrite previously set values by default to prevent default config files to supersede DB Config.
- *
- * The config format is PHP array and the template for configuration files is the following:
- *
- * <?php return [
- * 'section' => [
- * 'key' => 'value',
- * ],
- * ];
- *
- * @param string $filepath
- * @param bool $overwrite Force value overwrite if the config key already exists
- * @throws Exception
- */
- public function loadConfigFile($filepath, $overwrite = false)
- {
- if (!file_exists($filepath)) {
- throw new Exception('Error loading non-existent config file ' . $filepath);
- }
-
- $config = include($filepath);
-
- if (!is_array($config)) {
- throw new Exception('Error loading config file ' . $filepath);
- }
-
- $this->loadConfigArray($config, $overwrite);
- }
-
- /**
- * Loads addons configuration files
- *
- * First loads all activated addons default configuration through the load_config hook, then load the local.config.php
- * again to overwrite potential local addon configuration.
- */
- private function loadAddonConfig()
- {
- // Loads addons default config
- Core\Hook::callAll('load_config');
-
- // Load the local addon config file to overwritten default addon config values
- if (file_exists($this->getBasePath() . '/config/addon.config.php')) {
- $this->loadConfigFile($this->getBasePath() . '/config/addon.config.php', true);
- } elseif (file_exists($this->getBasePath() . '/config/addon.ini.php')) {
- $this->loadINIConfigFile($this->getBasePath() . '/config/addon.ini.php', true);
- }
- }
-
- /**
- * 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
- */
- private function loadConfigArray(array $config, $overwrite = false)
- {
- foreach ($config as $category => $values) {
- foreach ($values as $key => $value) {
- if ($overwrite) {
- $this->setConfigValue($category, $key, $value);
- } else {
- $this->setDefaultConfigValue($category, $key, $value);
- }
- }
- }
- }
-
/**
* Loads the default timezone
*
*/
private function loadDefaultTimezone()
{
- if ($this->getConfigValue('system', 'default_timezone')) {
- $this->timezone = $this->getConfigValue('system', 'default_timezone');
+ if ($this->config->get('system', 'default_timezone')) {
+ $this->timezone = $this->config->get('system', 'default_timezone');
} else {
global $default_timezone;
$this->timezone = !empty($default_timezone) ? $default_timezone : 'UTC';
$relative_script_path = defaults($_SERVER, 'SCRIPT_URL' , $relative_script_path);
$relative_script_path = defaults($_SERVER, 'REQUEST_URI' , $relative_script_path);
- $this->urlPath = $this->getConfigValue('system', 'urlpath');
+ $this->urlPath = $this->config->get('system', 'urlpath');
/* $relative_script_path gives /relative/path/to/friendica/module/parameter
* QUERY_STRING gives pagename=module/parameter
return;
}
- $db_host = $this->getConfigValue('database', 'hostname');
- $db_user = $this->getConfigValue('database', 'username');
- $db_pass = $this->getConfigValue('database', 'password');
- $db_data = $this->getConfigValue('database', 'database');
- $charset = $this->getConfigValue('database', 'charset');
+ $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'))
$stamp1 = microtime(true);
- if (DBA::connect($db_host, $db_user, $db_pass, $db_data, $charset)) {
+ if (DBA::connect($this->config, $db_host, $db_user, $db_pass, $db_data, $charset)) {
// Loads DB_UPDATE_VERSION constant
- Database\DBStructure::definition(false);
+ Database\DBStructure::definition($this->basePath, false);
}
unset($db_host, $db_user, $db_pass, $db_data, $charset);
$this->saveTimestamp($stamp1, 'network');
}
- /**
- * @brief Returns the base filesystem path of the App
- *
- * It first checks for the internal variable, then for DOCUMENT_ROOT and
- * finally for PWD
- *
- * @return string
- * @throws InternalServerErrorException
- */
- public function getBasePath()
- {
- $basepath = $this->basePath;
-
- if (!$basepath) {
- $basepath = Core\Config::get('system', 'basepath');
- }
-
- if (!$basepath && !empty($_SERVER['DOCUMENT_ROOT'])) {
- $basepath = $_SERVER['DOCUMENT_ROOT'];
- }
-
- if (!$basepath && !empty($_SERVER['PWD'])) {
- $basepath = $_SERVER['PWD'];
- }
-
- return self::getRealPath($basepath);
- }
-
- /**
- * @brief Returns a normalized file path
- *
- * This is a wrapper for the "realpath" function.
- * That function cannot detect the real path when some folders aren't readable.
- * Since this could happen with some hosters we need to handle this.
- *
- * @param string $path The path that is about to be normalized
- * @return string normalized path - when possible
- */
- public static function getRealPath($path)
- {
- $normalized = realpath($path);
-
- if (!is_bool($normalized)) {
- return $normalized;
- } else {
- return $path;
- }
- }
-
public function getScheme()
{
return $this->scheme;
$this->urlPath = trim($parsed['path'], '\\/');
}
- if (file_exists($this->getBasePath() . '/.htpreconfig.php')) {
- include $this->getBasePath() . '/.htpreconfig.php';
+ if (file_exists($this->basePath . '/.htpreconfig.php')) {
+ include $this->basePath . '/.htpreconfig.php';
}
if (Core\Config::get('config', 'hostname') != '') {
// compose the page title from the sitename and the
// current module called
if (!$this->module == '') {
- $this->page['title'] = $this->config['sitename'] . ' (' . $this->module . ')';
+ $this->page['title'] = $this->config->get('config', 'sitename') . ' (' . $this->module . ')';
} else {
- $this->page['title'] = $this->config['sitename'];
+ $this->page['title'] = $this->config->get('config', 'sitename');
}
if (!empty(Core\Renderer::$theme['stylesheet'])) {
*/
public function saveTimestamp($timestamp, $value)
{
- if (!isset($this->config['system']['profiler']) || !$this->config['system']['profiler']) {
+ $profiler = $this->config->get('system', 'profiler');
+
+ if (!isset($profiler) || !$profiler) {
return;
}
return;
}
- $cmdline = $this->getConfigValue('config', 'php_path', 'php') . ' ' . escapeshellarg($command);
+ $cmdline = $this->config->get('config', 'php_path', 'php') . ' ' . escapeshellarg($command);
foreach ($args as $key => $value) {
if (!is_null($value) && is_bool($value) && !$value) {
}
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
- $resource = proc_open('cmd /c start /b ' . $cmdline, [], $foo, $this->getBasePath());
+ $resource = proc_open('cmd /c start /b ' . $cmdline, [], $foo, $this->basePath);
} else {
- $resource = proc_open($cmdline . ' &', [], $foo, $this->getBasePath());
+ $resource = proc_open($cmdline . ' &', [], $foo, $this->basePath);
}
if (!is_resource($resource)) {
Core\Logger::log('We got no resource for command ' . $cmdline, Core\Logger::DEBUG);
proc_close($resource);
}
- /**
- * @brief Returns the system user that is executing the script
- *
- * This mostly returns something like "www-data".
- *
- * @return string system username
- */
- private static function getSystemUser()
- {
- if (!function_exists('posix_getpwuid') || !function_exists('posix_geteuid')) {
- return '';
- }
-
- $processUser = posix_getpwuid(posix_geteuid());
- return $processUser['name'];
- }
-
- /**
- * @brief Checks if a given directory is usable for the system
- *
- * @param $directory
- * @param bool $check_writable
- * @return boolean the directory is usable
- * @throws Exception
- */
- public static function isDirectoryUsable($directory, $check_writable = true)
- {
- if ($directory == '') {
- Core\Logger::log('Directory is empty. This shouldn\'t happen.', Core\Logger::DEBUG);
- return false;
- }
-
- if (!file_exists($directory)) {
- Core\Logger::log('Path "' . $directory . '" does not exist for user ' . self::getSystemUser(), Core\Logger::DEBUG);
- return false;
- }
-
- if (is_file($directory)) {
- Core\Logger::log('Path "' . $directory . '" is a file for user ' . self::getSystemUser(), Core\Logger::DEBUG);
- return false;
- }
-
- if (!is_dir($directory)) {
- Core\Logger::log('Path "' . $directory . '" is not a directory for user ' . self::getSystemUser(), Core\Logger::DEBUG);
- return false;
- }
-
- if ($check_writable && !is_writable($directory)) {
- Core\Logger::log('Path "' . $directory . '" is not writable for user ' . self::getSystemUser(), Core\Logger::DEBUG);
- return false;
- }
-
- return true;
- }
-
- /**
- * @param string $cat Config category
- * @param string $k Config key
- * @param mixed $default Default value if it isn't set
- *
- * @return string Returns the value of the Config entry
- */
- public function getConfigValue($cat, $k, $default = null)
- {
- $return = $default;
-
- if ($cat === 'config') {
- if (isset($this->config[$k])) {
- $return = $this->config[$k];
- }
- } else {
- if (isset($this->config[$cat][$k])) {
- $return = $this->config[$cat][$k];
- }
- }
-
- 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 setDefaultConfigValue($cat, $k, $v)
- {
- if (!isset($this->config[$cat][$k])) {
- $this->setConfigValue($cat, $k, $v);
- }
- }
-
- /**
- * Sets a value in the config cache. Accepts raw output from the config table
- *
- * @param string $cat Config category
- * @param string $k Config key
- * @param mixed $v Value to set
- */
- public function setConfigValue($cat, $k, $v)
- {
- // Only arrays are serialized in database, so we have to unserialize sparingly
- $value = is_string($v) && preg_match("|^a:[0-9]+:{.*}$|s", $v) ? unserialize($v) : $v;
-
- if ($cat === 'config') {
- $this->config[$k] = $value;
- } else {
- if (!isset($this->config[$cat])) {
- $this->config[$cat] = [];
- }
-
- $this->config[$cat][$k] = $value;
- }
- }
-
- /**
- * Deletes a value from the config cache
- *
- * @param string $cat Config category
- * @param string $k Config key
- */
- public function deleteConfigValue($cat, $k)
- {
- if ($cat === 'config') {
- if (isset($this->config[$k])) {
- unset($this->config[$k]);
- }
- } else {
- if (isset($this->config[$cat][$k])) {
- unset($this->config[$cat][$k]);
- }
- }
- }
-
-
- /**
- * Retrieves a value from the user config cache
- *
- * @param int $uid User Id
- * @param string $cat Config category
- * @param string $k Config key
- * @param mixed $default Default value if key isn't set
- *
- * @return string The value of the config entry
- */
- public function getPConfigValue($uid, $cat, $k, $default = null)
- {
- $return = $default;
-
- if (isset($this->config[$uid][$cat][$k])) {
- $return = $this->config[$uid][$cat][$k];
- }
-
- return $return;
- }
-
- /**
- * 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 $k Config key
- * @param mixed $v Value to set
- */
- public function setPConfigValue($uid, $cat, $k, $v)
- {
- // Only arrays are serialized in database, so we have to unserialize sparingly
- $value = is_string($v) && preg_match("|^a:[0-9]+:{.*}$|s", $v) ? unserialize($v) : $v;
-
- 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] = [];
- }
-
- $this->config[$uid][$cat][$k] = $value;
- }
-
- /**
- * Deletes a value from the user config cache
- *
- * @param int $uid User Id
- * @param string $cat Config category
- * @param string $k Config key
- */
- public function deletePConfigValue($uid, $cat, $k)
- {
- if (isset($this->config[$uid][$cat][$k])) {
- unset($this->config[$uid][$cat][$k]);
- }
- }
-
/**
* Generates the site's default sender email address
*
$this->module = 'maintenance';
} else {
$this->checkURL();
- Core\Update::check(false);
+ Core\Update::check($this->basePath, false);
Core\Addon::loadAddons();
Core\Hook::loadHooks();
}
require_once 'boot.php';
-use Friendica\Util\LoggerFactory;
+use Friendica\Network\HTTPException\InternalServerErrorException;
/**
* Basic object
public static function getApp()
{
if (empty(self::$app)) {
- $logger = $logger = LoggerFactory::create('app');
- self::$app = new App(dirname(__DIR__), $logger);
+ throw new InternalServerErrorException('App isn\'t initialized.');
}
return self::$app;
*/
class Addon extends BaseObject
{
+ /**
+ * The addon sub-directory
+ * @var string
+ */
+ const DIRECTORY = 'addon';
+
/**
* List of the names of enabled addons
*
@include_once('addon/' . $addon . '/' . $addon . '.php');
if (function_exists($addon . '_install')) {
$func = $addon . '_install';
- $func();
+ $func(self::getApp());
$addon_admin = (function_exists($addon . "_addon_admin") ? 1 : 0);
if (function_exists($addon . '_uninstall')) {
$func = $addon . '_uninstall';
- $func();
+ $func(self::getApp());
}
if (function_exists($addon . '_install')) {
$func = $addon . '_install';
- $func();
+ $func(self::getApp());
}
DBA::update('addon', ['timestamp' => $t], ['id' => $i['id']]);
}
*/
namespace Friendica\Core;
-use Friendica\App;
-use Friendica\BaseObject;
+use Friendica\Core\Config\ConfigCache;
+use Friendica\Core\Config\IConfigAdapter;
+use Friendica\Core\Config\IConfigCache;
/**
* @brief Arbitrary system configuration storage
* If we ever would decide to return exactly the variable type as entered,
* we will have fun with the additional features. :-)
*/
-class Config extends BaseObject
+class Config
{
/**
- * @var \Friendica\Core\Config\IConfigAdapter
+ * @var Config\IConfigAdapter
*/
- private static $adapter = null;
+ private static $adapter;
- public static function init()
+ /**
+ * @var Config\IConfigCache
+ */
+ private static $cache;
+
+ /**
+ * Initialize the config with only the cache
+ *
+ * @param Config\IConfigCache $cache The configuration cache
+ */
+ public static function init(Config\IConfigCache $cache)
{
- // Database isn't ready or populated yet
- if (!self::getApp()->getMode()->has(App\Mode::DBCONFIGAVAILABLE)) {
- return;
- }
+ self::$cache = $cache;
+ }
- if (self::getApp()->getConfigValue('system', 'config_adapter') == 'preload') {
- self::$adapter = new Config\PreloadConfigAdapter();
- } else {
- self::$adapter = new Config\JITConfigAdapter();
- }
+ /**
+ * Add the adapter for DB-backend
+ *
+ * @param Config\IConfigAdapter $adapter
+ */
+ public static function setAdapter(Config\IConfigAdapter $adapter)
+ {
+ self::$adapter = $adapter;
}
/**
* @brief Loads all configuration values of family into a cached storage.
*
- * All configuration values of the system are stored in global cache
- * which is available under the global variable $a->config
+ * All configuration values of the system are stored in the cache ( @see IConfigCache )
*
* @param string $family The category of the configuration value
*
* @return void
- * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function load($family = "config")
{
- // Database isn't ready or populated yet
- if (!self::getApp()->getMode()->has(App\Mode::DBCONFIGAVAILABLE)) {
+ if (!isset(self::$adapter)) {
return;
}
- if (empty(self::$adapter)) {
- self::init();
- }
-
self::$adapter->load($family);
}
* ($family) and a key.
*
* Get a particular config value from the given category ($family)
- * and the $key from a cached storage in $a->config[$uid].
- * $instore is only used by the set_config function
- * to determine if the key already exists in the DB
- * If a key is found in the DB but doesn't exist in
- * local config cache, pull it into the cache so we don't have
- * to hit the DB again for this item.
+ * 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 $key The configuration key to query
* @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
- * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function get($family, $key, $default_value = null, $refresh = false)
{
- // Database isn't ready or populated yet, fallback to file config
- if (!self::getApp()->getMode()->has(App\Mode::DBCONFIGAVAILABLE)) {
- return self::getApp()->getConfigValue($family, $key, $default_value);
- }
-
- if (empty(self::$adapter)) {
- self::init();
+ if (!isset(self::$adapter)) {
+ return self::$cache->get($family, $key, $default_value);
}
return self::$adapter->get($family, $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)
- * for the user_id $uid.
*
* Note: Please do not store booleans - convert to 0/1 integer values!
*
* @param mixed $value The value to store
*
* @return bool Operation success
- * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function set($family, $key, $value)
{
- // Database isn't ready or populated yet
- if (!self::getApp()->getMode()->has(App\Mode::DBCONFIGAVAILABLE)) {
- return false;
- }
-
- if (empty(self::$adapter)) {
- self::init();
+ if (!isset(self::$adapter)) {
+ self::$cache->set($family, $key, $value);
+ return true;
}
return self::$adapter->set($family, $key, $value);
/**
* @brief Deletes the given key from the system configuration.
*
- * Removes the configured value from the stored cache in $a->config
- * and removes it from the database.
+ * 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 $key The configuration key to delete
*
* @return mixed
- * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function delete($family, $key)
{
- // Database isn't ready or populated yet
- if (!self::getApp()->getMode()->has(App\Mode::DBCONFIGAVAILABLE)) {
- return false;
- }
-
- if (empty(self::$adapter)) {
- self::init();
+ if (!isset(self::$adapter)) {
+ self::$cache->delete($family, $key);
}
return self::$adapter->delete($family, $key);
--- /dev/null
+<?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->config = $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;
+ }
+ }
+
+ /**
+ * {@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]);
+ }
+ }
+ }
+
+ /**
+ * {@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]);
+ }
+ }
+
+ /**
+ * Returns the whole configuration
+ *
+ * @return array The configuration
+ */
+ public function getAll()
+ {
+ return $this->config;
+ }
+}
--- /dev/null
+<?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)
+ {
+ if (!file_exists($filepath)) {
+ throw new \Exception('Error parsing non-existent INI config file ' . $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)
+ {
+ if (!file_exists($filepath)) {
+ throw new \Exception('Error loading non-existent config file ' . $filepath);
+ }
+
+ $config = include($filepath);
+
+ if (!is_array($config)) {
+ throw new \Exception('Error loading config file ' . $filepath);
+ }
+
+ return $config;
+ }
+}
interface IConfigAdapter
{
/**
- * @brief Loads all configuration values into a cached storage.
- *
- * All configuration values of the system are stored in global cache
- * which is available under the global variable $a->config
+ * Loads all configuration values into a cached storage.
*
* @param string $cat The category of the configuration values to load
*
public function load($cat = "config");
/**
- * @brief Get a particular user's config variable given the category name
+ * 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 in $a->config[$uid].
- * $instore is only used by the set_config function
- * to determine if the key already exists in the DB
- * If a key is found in the DB but doesn't exist in
- * local config cache, pull it into the cache so we don't have
- * to hit the DB again for this item.
- *
* @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)
public function get($cat, $k, $default_value = null, $refresh = false);
/**
- * @brief Sets a configuration value for system config
- *
* Stores a config value ($value) in the category ($family) under the key ($key)
* for the user_id $uid.
*
public function set($cat, $k, $value);
/**
- * @brief Deletes the given key from the system configuration.
- *
- * Removes the configured value from the stored cache in $a->config
+ * Removes the configured value from the stored cache
* and removes it from the database.
*
* @param string $cat The category of the configuration value
--- /dev/null
+<?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
+ */
+ 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();
+}
interface IPConfigAdapter
{
/**
- * @brief Loads all configuration values of a user's config family into a cached storage.
- *
- * All configuration values of the given user are stored in global cache
- * which is available under the global variable $a->config[$uid].
+ * 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
public function load($uid, $cat);
/**
- * @brief Get a particular user's config variable given the category name
+ * 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 from a cached storage in $a->config[$uid].
- *
* @param string $uid The user_id
* @param string $cat The category of the configuration value
* @param string $k The configuration key to query
public function get($uid, $cat, $k, $default_value = null, $refresh = false);
/**
- * @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.
*
public function set($uid, $cat, $k, $value);
/**
- * @brief Deletes the given key from the users's configuration.
- *
- * Removes the configured value from the stored cache in $a->config[$uid]
+ * Removes the configured value from the stored cache
* and removes it from the database.
*
* @param string $uid The user_id
--- /dev/null
+<?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();
+}
<?php
namespace Friendica\Core\Config;
-use Friendica\BaseObject;
use Friendica\Database\DBA;
/**
*
* @author Hypolite Petovan <hypolite@mrpetovan.com>
*/
-class JITConfigAdapter extends BaseObject implements IConfigAdapter
+class JITConfigAdapter 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;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
public function load($cat = "config")
{
// We don't preload "system" anymore.
while ($config = DBA::fetch($configs)) {
$k = $config['k'];
- self::getApp()->setConfigValue($cat, $k, $config['v']);
+ $this->configCache->set($cat, $k, $config['v']);
if ($cat !== 'config') {
$this->cache[$cat][$k] = $config['v'];
DBA::close($configs);
}
+ /**
+ * {@inheritdoc}
+ */
public function get($cat, $k, $default_value = null, $refresh = false)
{
- $a = self::getApp();
-
if (!$refresh) {
// Do we have the cached value? Then return it
if (isset($this->cache[$cat][$k])) {
$this->cache[$cat][$k] = $value;
$this->in_db[$cat][$k] = true;
return $value;
- } elseif (isset($a->config[$cat][$k])) {
+ } elseif ($this->configCache->get($cat, $k) !== null) {
// Assign the value (mostly) from config/local.config.php file to the cache
- $this->cache[$cat][$k] = $a->config[$cat][$k];
+ $this->cache[$cat][$k] = $this->configCache->get($cat, $k);
$this->in_db[$cat][$k] = false;
- return $a->config[$cat][$k];
- } elseif (isset($a->config[$k])) {
+ 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] = $a->config[$k];
+ $this->cache[$k] = $this->configCache->get('config', $k);
$this->in_db[$k] = false;
- return $a->config[$k];
+ return $this->configCache->get('config', $k);
}
$this->cache[$cat][$k] = '!<unset>!';
return $default_value;
}
+ /**
+ * {@inheritdoc}
+ */
public function set($cat, $k, $value)
{
// We store our setting values in a string variable.
return true;
}
- self::getApp()->setConfigValue($cat, $k, $value);
+ $this->configCache->set($cat, $k, $value);
// Assign the just added value to the cache
$this->cache[$cat][$k] = $dbvalue;
return $result;
}
+ /**
+ * {@inheritdoc}
+ */
public function delete($cat, $k)
{
if (isset($this->cache[$cat][$k])) {
<?php
namespace Friendica\Core\Config;
-use Friendica\BaseObject;
use Friendica\Database\DBA;
/**
*
* @author Hypolite Petovan <hypolite@mrpetovan.com>
*/
-class JITPConfigAdapter extends BaseObject implements IPConfigAdapter
+class JITPConfigAdapter implements IPConfigAdapter
{
private $in_db;
- public function load($uid, $cat)
+ /**
+ * The config cache of this adapter
+ * @var IPConfigCache
+ */
+ private $configCache;
+
+ /**
+ * @param IPConfigCache $configCache The config cache of this adapter
+ */
+ public function __construct(IPConfigCache $configCache)
{
- $a = self::getApp();
+ $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'];
- self::getApp()->setPConfigValue($uid, $cat, $k, $pconfig['v']);
+ $this->configCache->setP($uid, $cat, $k, $pconfig['v']);
$this->in_db[$uid][$cat][$k] = true;
}
} else if ($cat != 'config') {
// Negative caching
- $a->config[$uid][$cat] = "!<unset>!";
+ $this->configCache->setP($uid, $cat, null, "!<unset>!");
}
DBA::close($pconfigs);
}
+ /**
+ * {@inheritdoc}
+ */
public function get($uid, $cat, $k, $default_value = null, $refresh = false)
{
- $a = self::getApp();
-
if (!$refresh) {
// Looking if the whole family isn't set
- if (isset($a->config[$uid][$cat])) {
- if ($a->config[$uid][$cat] === '!<unset>!') {
+ if ($this->configCache->getP($uid, $cat) !== null) {
+ if ($this->configCache->getP($uid, $cat) === '!<unset>!') {
return $default_value;
}
}
- if (isset($a->config[$uid][$cat][$k])) {
- if ($a->config[$uid][$cat][$k] === '!<unset>!') {
+ if ($this->configCache->getP($uid, $cat, $k) !== null) {
+ if ($this->configCache->getP($uid, $cat, $k) === '!<unset>!') {
return $default_value;
}
- return $a->config[$uid][$cat][$k];
+ return $this->configCache->getP($uid, $cat, $k);
}
}
if (DBA::isResult($pconfig)) {
$val = (preg_match("|^a:[0-9]+:{.*}$|s", $pconfig['v']) ? unserialize($pconfig['v']) : $pconfig['v']);
- self::getApp()->setPConfigValue($uid, $cat, $k, $val);
+ $this->configCache->setP($uid, $cat, $k, $val);
$this->in_db[$uid][$cat][$k] = true;
return $val;
} else {
- self::getApp()->setPConfigValue($uid, $cat, $k, '!<unset>!');
+ $this->configCache->setP($uid, $cat, $k, '!<unset>!');
$this->in_db[$uid][$cat][$k] = false;
}
}
+ /**
+ * {@inheritdoc}
+ */
public function set($uid, $cat, $k, $value)
{
// We store our setting values in a string variable.
return true;
}
- self::getApp()->setPConfigValue($uid, $cat, $k, $value);
+ $this->configCache->setP($uid, $cat, $k, $value);
// manage array value
$dbvalue = (is_array($value) ? serialize($value) : $dbvalue);
return $result;
}
+ /**
+ * {@inheritdoc}
+ */
public function delete($uid, $cat, $k)
{
- self::getApp()->deletePConfigValue($uid, $cat, $k);
+ $this->configCache->deleteP($uid, $cat, $k);
if (!empty($this->in_db[$uid][$cat][$k])) {
unset($this->in_db[$uid][$cat][$k]);
namespace Friendica\Core\Config;
use Exception;
-use Friendica\BaseObject;
use Friendica\Database\DBA;
/**
*
* @author Hypolite Petovan <hypolite@mrpetovan.com>
*/
-class PreloadConfigAdapter extends BaseObject implements IConfigAdapter
+class PreloadConfigAdapter implements IConfigAdapter
{
private $config_loaded = false;
- public function __construct()
+ /**
+ * @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->load();
}
+ /**
+ * {@inheritdoc}
+ */
public function load($family = 'config')
{
if ($this->config_loaded) {
$configs = DBA::select('config', ['cat', 'v', 'k']);
while ($config = DBA::fetch($configs)) {
- self::getApp()->setConfigValue($config['cat'], $config['k'], $config['v']);
+ $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 ($refresh) {
$config = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $k]);
if (DBA::isResult($config)) {
- self::getApp()->setConfigValue($cat, $k, $config['v']);
+ $this->configCache->set($cat, $k, $config['v']);
}
}
- $return = self::getApp()->getConfigValue($cat, $k, $default_value);
+ $return = $this->configCache->get($cat, $k, $default_value);
return $return;
}
+ /**
+ * {@inheritdoc}
+ */
public function set($cat, $k, $value)
{
// We store our setting values as strings.
// The exception are array values.
$compare_value = !is_array($value) ? (string)$value : $value;
- if (self::getApp()->getConfigValue($cat, $k) === $compare_value) {
+ if ($this->configCache->get($cat, $k) === $compare_value) {
return true;
}
- self::getApp()->setConfigValue($cat, $k, $value);
+ $this->configCache->set($cat, $k, $value);
// manage array value
$dbvalue = is_array($value) ? serialize($value) : $value;
return true;
}
+ /**
+ * {@inheritdoc}
+ */
public function delete($cat, $k)
{
- self::getApp()->deleteConfigValue($cat, $k);
+ $this->configCache->delete($cat, $k);
$result = DBA::delete('config', ['cat' => $cat, 'k' => $k]);
namespace Friendica\Core\Config;
use Exception;
-use Friendica\BaseObject;
use Friendica\Database\DBA;
/**
*
* @author Hypolite Petovan <hypolite@mrpetovan.com>
*/
-class PreloadPConfigAdapter extends BaseObject implements IPConfigAdapter
+class PreloadPConfigAdapter implements IPConfigAdapter
{
private $config_loaded = false;
- public function __construct($uid)
+ /**
+ * 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->load($uid, 'config');
+ $this->configCache = $configCache;
+ if (isset($uid)) {
+ $this->load($uid, 'config');
+ }
}
+ /**
+ * {@inheritdoc}
+ */
public function load($uid, $family)
{
if ($this->config_loaded) {
$pconfigs = DBA::select('pconfig', ['cat', 'v', 'k'], ['uid' => $uid]);
while ($pconfig = DBA::fetch($pconfigs)) {
- self::getApp()->setPConfigValue($uid, $pconfig['cat'], $pconfig['k'], $pconfig['v']);
+ $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) {
if ($refresh) {
$config = DBA::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
if (DBA::isResult($config)) {
- self::getApp()->setPConfigValue($uid, $cat, $k, $config['v']);
+ $this->configCache->setP($uid, $cat, $k, $config['v']);
} else {
- self::getApp()->deletePConfigValue($uid, $cat, $k);
+ $this->configCache->deleteP($uid, $cat, $k);
}
}
- $return = self::getApp()->getPConfigValue($uid, $cat, $k, $default_value);
-
- return $return;
+ return $this->configCache->getP($uid, $cat, $k, $default_value);;
}
+ /**
+ * {@inheritdoc}
+ */
public function set($uid, $cat, $k, $value)
{
if (!$this->config_loaded) {
// The exception are array values.
$compare_value = !is_array($value) ? (string)$value : $value;
- if (self::getApp()->getPConfigValue($uid, $cat, $k) === $compare_value) {
+ if ($this->configCache->getP($uid, $cat, $k) === $compare_value) {
return true;
}
- self::getApp()->setPConfigValue($uid, $cat, $k, $value);
+ $this->configCache->setP($uid, $cat, $k, $value);
// manage array value
$dbvalue = is_array($value) ? serialize($value) : $value;
return true;
}
+ /**
+ * {@inheritdoc}
+ */
public function delete($uid, $cat, $k)
{
if (!$this->config_loaded) {
$this->load($uid, $cat);
}
- self::getApp()->deletePConfigValue($uid, $cat, $k);
+ $this->configCache->deleteP($uid, $cat, $k);
$result = DBA::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
}
}
- $db_host = $a->getConfigValue('database', 'hostname');
- $db_user = $a->getConfigValue('database', 'username');
- $db_pass = $a->getConfigValue('database', 'password');
- $db_data = $a->getConfigValue('database', 'database');
+ $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');
} else {
// Creating config file
$this->out("Creating config file...\n");
$installer->resetChecks();
- if (!$installer->installDatabase()) {
+ if (!$installer->installDatabase($a->getBasePath())) {
$errorMessage = $this->extractErrors($installer->getChecks());
throw new RuntimeException($errorMessage);
}
if (is_array($value)) {
foreach ($value as $k => $v) {
- $this->out("{$cat}.{$key}[{$k}] => " . $v);
+ $this->out("{$cat}.{$key}[{$k}] => " . (is_array($v) ? implode(', ', $v) : $v));
}
} else {
$this->out("{$cat}.{$key} => " . $value);
$cat = $this->getArgument(0);
Core\Config::load($cat);
- if (!is_null($a->config[$cat])) {
+ if ($a->getConfig()->get($cat) !== null) {
$this->out("[{$cat}]");
- foreach ($a->config[$cat] as $key => $value) {
+ $catVal = $a->getConfig()->get($cat);
+ foreach ($catVal as $key => $value) {
if (is_array($value)) {
foreach ($value as $k => $v) {
- $this->out("{$key}[{$k}] => " . $v);
+ $this->out("{$key}[{$k}] => " . (is_array($v) ? implode(', ', $v) : $v));
}
} else {
$this->out("{$key} => " . $value);
$this->out('Warning: The JIT (Just In Time) Config adapter doesn\'t support loading the entire configuration, showing file config only');
}
- foreach ($a->config as $cat => $section) {
+ $config = $a->getConfig()->getAll();
+ foreach ($config as $cat => $section) {
if (is_array($section)) {
foreach ($section as $key => $value) {
if (is_array($value)) {
foreach ($value as $k => $v) {
- $this->out("{$cat}.{$key}[{$k}] => " . $v);
+ $this->out("{$cat}.{$key}[{$k}] => " . (is_array($v) ? implode(', ', $v) : $v));
}
} else {
$this->out("{$cat}.{$key} => " . $value);
Core\Config::load();
+ $a = get_app();
+
switch ($this->getArgument(0)) {
case "dryrun":
- $output = DBStructure::update(true, false);
+ $output = DBStructure::update($a->getBasePath(), true, false);
break;
case "update":
$force = $this->getOption(['f', 'force'], false);
- $output = Update::run($force, true, false);
+ $output = Update::run($a->getBasePath(), $force, true, false);
break;
case "dumpsql":
ob_start();
- DBStructure::printStructure();
+ DBStructure::printStructure($a->getBasePath());
$output = ob_get_clean();
break;
case "toinnodb":
namespace Friendica\Core\Console;
-use Friendica\Core\L10n;
use Friendica\Core\Config;
+use Friendica\Core\L10n;
use Friendica\Core\Update;
/**
}
echo L10n::t('Check for pending update actions.') . "\n";
- Update::run(true, true, false);
+ Update::run($a->getBasePath(), true, true, false);
echo L10n::t('Done.') . "\n";
echo L10n::t('Execute pending post updates.') . "\n";
namespace Friendica\Core\Console;
+use Friendica\BaseObject;
+
/**
* Tired of chasing typos and finding them after a commit.
* Run this and quickly see if we've got any parse errors in our application files.
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
}
- $a = \get_app();
-
- $php_path = $a->getConfigValue('config', 'php_path', 'php');
+ $php_path = BaseObject::getApp()->getConfig()->get('config', 'php_path', 'php');
if ($this->getOption('v')) {
$this->out('Directory: src');
/***
* Installs the DB-Scheme for Friendica
*
+ * @param string $basePath The base path of this application
+ *
* @return bool true if the installation was successful, otherwise false
* @throws Exception
*/
- public function installDatabase()
+ public function installDatabase($basePath)
{
- $result = DBStructure::update(false, true, true);
+ $result = DBStructure::update($basePath, false, true, true);
if ($result) {
$txt = L10n::t('You may need to import the file "database.sql" manually using phpmyadmin or mysql.') . EOL;
namespace Friendica\Core;
use Friendica\BaseObject;
+use Friendica\Factory\LoggerFactory;
use Friendica\Network\HTTPException\InternalServerErrorException;
-use Friendica\Util\LoggerFactory;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
*/
namespace Friendica\Core;
-use Friendica\App;
-use Friendica\BaseObject;
-
/**
* @brief Management of user configuration storage
* Note:
* The PConfig::get() functions return boolean false for keys that are unset,
* and this could lead to subtle bugs.
*/
-class PConfig extends BaseObject
+class PConfig
{
/**
- * @var \Friendica\Core\Config\IPConfigAdapter
+ * @var Config\IPConfigAdapter
*/
- private static $adapter = null;
+ private static $adapter;
- public static function init($uid)
- {
- $a = self::getApp();
+ /**
+ * @var Config\IPConfigCache
+ */
+ private static $cache;
- // Database isn't ready or populated yet
- if (!$a->getMode()->has(App\Mode::DBCONFIGAVAILABLE)) {
- return;
- }
+ /**
+ * Initialize the config with only the cache
+ *
+ * @param Config\IPConfigCache $cache The configuration cache
+ */
+ public static function init(Config\IPConfigCache $cache)
+ {
+ self::$cache = $cache;
+ }
- if ($a->getConfigValue('system', 'config_adapter') == 'preload') {
- self::$adapter = new Config\PreloadPConfigAdapter($uid);
- } else {
- self::$adapter = new Config\JITPConfigAdapter();
- }
+ /**
+ * Add the adapter for DB-backend
+ *
+ * @param Config\IPConfigAdapter $adapter
+ */
+ public static function setAdapter(Config\IPConfigAdapter $adapter)
+ {
+ self::$adapter = $adapter;
}
/**
* @brief Loads all configuration values of a user's config family into a cached storage.
*
- * All configuration values of the given user are stored in global cache
- * which is available under the global variable $a->config[$uid].
+ * 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
*
* @return void
- * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function load($uid, $family)
{
- // Database isn't ready or populated yet
- if (!self::getApp()->getMode()->has(App\Mode::DBCONFIGAVAILABLE)) {
+ if (!isset(self::$adapter)) {
return;
}
- if (empty(self::$adapter)) {
- self::init($uid);
- }
-
self::$adapter->load($uid, $family);
}
* ($family) and a key.
*
* Get a particular user's config value from the given category ($family)
- * and the $key from a cached storage in $a->config[$uid].
+ * and the $key with the $uid from a cached storage either from the self::$adapter
+ * (@see IConfigAdapter ) or from the static::$cache (@see IConfigCache ).
*
* @param string $uid The user_id
* @param string $family The category of the configuration value
* @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
- * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function get($uid, $family, $key, $default_value = null, $refresh = false)
{
- // Database isn't ready or populated yet
- if (!self::getApp()->getMode()->has(App\Mode::DBCONFIGAVAILABLE)) {
- return;
- }
-
- if (empty(self::$adapter)) {
- self::init($uid);
+ if (!isset(self::$adapter)) {
+ return self::$cache->getP($uid, $family, $key, $default_value);
}
return self::$adapter->get($uid, $family, $key, $default_value, $refresh);
* @param mixed $value The value to store
*
* @return bool Operation success
- * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function set($uid, $family, $key, $value)
{
- // Database isn't ready or populated yet
- if (!self::getApp()->getMode()->has(App\Mode::DBCONFIGAVAILABLE)) {
- return false;
- }
-
- if (empty(self::$adapter)) {
- self::init($uid);
+ if (!isset(self::$adapter)) {
+ return self::$cache->setP($uid, $family, $key, $value);
}
return self::$adapter->set($uid, $family, $key, $value);
/**
* @brief Deletes the given key from the users's configuration.
*
- * Removes the configured value from the stored cache in $a->config[$uid]
- * and removes it from the database.
+ * 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
*
* @return mixed
- * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function delete($uid, $family, $key)
{
- // Database isn't ready or populated yet
- if (!self::getApp()->getMode()->has(App\Mode::DBCONFIGAVAILABLE)) {
- return false;
- }
-
- if (empty(self::$adapter)) {
- self::init($uid);
+ if (!isset(self::$adapter)) {
+ return self::$cache->deleteP($uid, $family, $key);
}
return self::$adapter->delete($uid, $family, $key);
exit();
}
+ /**
+ * @brief Returns the system user that is executing the script
+ *
+ * This mostly returns something like "www-data".
+ *
+ * @return string system username
+ */
+ public static function getUser()
+ {
+ if (!function_exists('posix_getpwuid') || !function_exists('posix_geteuid')) {
+ return '';
+ }
+
+ $processUser = posix_getpwuid(posix_geteuid());
+ return $processUser['name'];
+ }
+
+ /**
+ * @brief Checks if a given directory is usable for the system
+ *
+ * @param $directory
+ * @param bool $check_writable
+ *
+ * @return boolean the directory is usable
+ */
+ public static function isDirectoryUsable($directory, $check_writable = true)
+ {
+ if ($directory == '') {
+ Logger::log('Directory is empty. This shouldn\'t happen.', Logger::DEBUG);
+ return false;
+ }
+
+ if (!file_exists($directory)) {
+ Logger::log('Path "' . $directory . '" does not exist for user ' . static::getUser(), Logger::DEBUG);
+ return false;
+ }
+
+ if (is_file($directory)) {
+ Logger::log('Path "' . $directory . '" is a file for user ' . static::getUser(), Logger::DEBUG);
+ return false;
+ }
+
+ if (!is_dir($directory)) {
+ Logger::log('Path "' . $directory . '" is not a directory for user ' . static::getUser(), Logger::DEBUG);
+ return false;
+ }
+
+ if ($check_writable && !is_writable($directory)) {
+ Logger::log('Path "' . $directory . '" is not writable for user ' . static::getUser(), Logger::DEBUG);
+ return false;
+ }
+
+ return true;
+ }
+
/// @todo Move the following functions from boot.php
/*
function killme()
/**
* @brief Function to check if the Database structure needs an update.
*
+ * @param string $basePath The base path of this application
* @param boolean $via_worker boolean Is the check run via the worker?
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function check($via_worker)
+ public static function check($basePath, $via_worker)
{
if (!DBA::connected()) {
return;
if ($build < DB_UPDATE_VERSION) {
// When we cannot execute the database update via the worker, we will do it directly
if (!Worker::add(PRIORITY_CRITICAL, 'DBUpdate') && $via_worker) {
- self::run();
+ self::run($basePath);
}
}
}
/**
* Automatic database updates
*
- * @param bool $force Force the Update-Check even if the lock is set
- * @param bool $verbose Run the Update-Check verbose
- * @param bool $sendMail Sends a Mail to the administrator in case of success/failure
+ * @param string $basePath The base path of this application
+ * @param bool $force Force the Update-Check even if the lock is set
+ * @param bool $verbose Run the Update-Check verbose
+ * @param bool $sendMail Sends a Mail to the administrator in case of success/failure
*
* @return string Empty string if the update is successful, error messages otherwise
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function run($force = false, $verbose = false, $sendMail = true)
+ public static function run($basePath, $force = false, $verbose = false, $sendMail = true)
{
// In force mode, we release the dbupdate lock first
// Necessary in case of an stuck update
}
// update the structure in one call
- $retval = DBStructure::update($verbose, true);
+ $retval = DBStructure::update($basePath, $verbose, true);
if ($retval) {
if ($sendMail) {
self::updateFailed(
}
}
} elseif ($force) {
- DBStructure::update($verbose, true);
+ DBStructure::update($basePath, $verbose, true);
}
return '';
namespace Friendica\Database;
-// Do not use Core\Config in this class at risk of infinite loop.
-// Please use App->getConfigVariable() instead.
-//use Friendica\Core\Config;
-
+use Friendica\Core\Config\IConfigCache;
use Friendica\Core\Logger;
use Friendica\Core\System;
use Friendica\Util\DateTimeFormat;
public static $connected = false;
+ /**
+ * @var IConfigCache
+ */
+ private static $configCache;
private static $server_info = '';
private static $connection;
private static $driver;
private static $db_name = '';
private static $db_charset = '';
- public static function connect($serveraddr, $user, $pass, $db, $charset = null)
+ public static function connect($configCache, $serveraddr, $user, $pass, $db, $charset = null)
{
if (!is_null(self::$connection) && self::connected()) {
return true;
}
// We are storing these values for being able to perform a reconnect
+ self::$configCache = $configCache;
self::$db_serveraddr = $serveraddr;
self::$db_user = $user;
self::$db_pass = $pass;
public static function reconnect() {
self::disconnect();
- $ret = self::connect(self::$db_serveraddr, self::$db_user, self::$db_pass, self::$db_name, self::$db_charset);
+ $ret = self::connect(self::$configCache, self::$db_serveraddr, self::$db_user, self::$db_pass, self::$db_name, self::$db_charset);
return $ret;
}
* @throws \Exception
*/
private static function logIndex($query) {
- $a = \get_app();
- if (!$a->getConfigVariable('system', 'db_log_index')) {
+ if (!self::$configCache->get('system', 'db_log_index')) {
return;
}
return;
}
- $watchlist = explode(',', $a->getConfigVariable('system', 'db_log_index_watch'));
- $blacklist = explode(',', $a->getConfigVariable('system', 'db_log_index_blacklist'));
+ $watchlist = explode(',', self::$configCache->get('system', 'db_log_index_watch'));
+ $blacklist = explode(',', self::$configCache->get('system', 'db_log_index_blacklist'));
while ($row = self::fetch($r)) {
- if ((intval($a->getConfigVariable('system', 'db_loglimit_index')) > 0)) {
+ if ((intval(self::$configCache->get('system', 'db_loglimit_index')) > 0)) {
$log = (in_array($row['key'], $watchlist) &&
- ($row['rows'] >= intval($a->getConfigVariable('system', 'db_loglimit_index'))));
+ ($row['rows'] >= intval(self::$configCache->get('system', 'db_loglimit_index'))));
} else {
$log = false;
}
- if ((intval($a->getConfigVariable('system', 'db_loglimit_index_high')) > 0) && ($row['rows'] >= intval($a->getConfigVariable('system', 'db_loglimit_index_high')))) {
+ if ((intval(self::$configCache->get('system', 'db_loglimit_index_high')) > 0) && ($row['rows'] >= intval(self::$configCache->get('system', 'db_loglimit_index_high')))) {
$log = true;
}
if ($log) {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
- @file_put_contents($a->getConfigVariable('system', 'db_log_index'), DateTimeFormat::utcNow()."\t".
+ @file_put_contents(self::$configCache->get('system', 'db_log_index'), DateTimeFormat::utcNow()."\t".
$row['key']."\t".$row['rows']."\t".$row['Extra']."\t".
basename($backtrace[1]["file"])."\t".
$backtrace[1]["line"]."\t".$backtrace[2]["function"]."\t".
$orig_sql = $sql;
- if ($a->getConfigValue('system', 'db_callstack')) {
+ if (self::$configCache->get('system', 'db_callstack') !== null) {
$sql = "/*".System::callstack()." */ ".$sql;
}
$a->saveTimestamp($stamp1, 'database');
- if ($a->getConfigValue('system', 'db_log')) {
+ if (self::$configCache->get('system', 'db_log')) {
$stamp2 = microtime(true);
$duration = (float)($stamp2 - $stamp1);
- if (($duration > $a->getConfigValue('system', 'db_loglimit'))) {
+ if (($duration > self::$configCache->get('system', 'db_loglimit'))) {
$duration = round($duration, 3);
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
- @file_put_contents($a->getConfigValue('system', 'db_log'), DateTimeFormat::utcNow()."\t".$duration."\t".
+ @file_put_contents(self::$configCache->get('system', 'db_log'), DateTimeFormat::utcNow()."\t".$duration."\t".
basename($backtrace[1]["file"])."\t".
$backtrace[1]["line"]."\t".$backtrace[2]["function"]."\t".
substr(self::replaceParameters($sql, $args), 0, 2000)."\n", FILE_APPEND);
* This process must only be started once, since the value is cached.
*/
private static function buildRelationData() {
- $definition = DBStructure::definition();
+ $definition = DBStructure::definition(self::$configCache->get('system', 'basepath'));
foreach ($definition AS $table => $structure) {
foreach ($structure['fields'] AS $field => $field_struct) {
return L10n::t('Errors encountered performing database changes: ') . $message . EOL;
}
- public static function printStructure()
+ public static function printStructure($basePath)
{
- $database = self::definition(false);
+ $database = self::definition($basePath, false);
echo "-- ------------------------------------------\n";
echo "-- " . FRIENDICA_PLATFORM . " " . FRIENDICA_VERSION . " (" . FRIENDICA_CODENAME, ")\n";
*
* @see config/dbstructure.config.php
* @param boolean $with_addons_structure Whether to tack on addons additional tables
+ * @param string $basePath The base path of this application
* @return array
* @throws Exception
*/
- public static function definition($with_addons_structure = true)
+ public static function definition($basePath, $with_addons_structure = true)
{
if (!self::$definition) {
- $a = \Friendica\BaseObject::getApp();
- $filename = $a->getBasePath() . '/config/dbstructure.config.php';
+ $filename = $basePath . '/config/dbstructure.config.php';
if (!is_readable($filename)) {
throw new Exception('Missing database structure config file config/dbstructure.config.php');
/**
* Updates DB structure and returns eventual errors messages
*
- * @param bool $verbose
- * @param bool $action Whether to actually apply the update
- * @param bool $install Is this the initial update during the installation?
- * @param array $tables An array of the database tables
- * @param array $definition An array of the definition tables
+ * @param string $basePath The base path of this application
+ * @param bool $verbose
+ * @param bool $action Whether to actually apply the update
+ * @param bool $install Is this the initial update during the installation?
+ * @param array $tables An array of the database tables
+ * @param array $definition An array of the definition tables
* @return string Empty string if the update is successful, error messages otherwise
* @throws Exception
*/
- public static function update($verbose, $action, $install = false, array $tables = null, array $definition = null)
+ public static function update($basePath, $verbose, $action, $install = false, array $tables = null, array $definition = null)
{
if ($action && !$install) {
Config::set('system', 'maintenance', 1);
// Get the definition
if (is_null($definition)) {
- $definition = self::definition();
+ $definition = self::definition($basePath);
}
// MySQL >= 5.7.4 doesn't support the IGNORE keyword in ALTER TABLE statements
--- /dev/null
+<?php
+
+namespace Friendica\Factory;
+
+use Friendica\Core\Config;
+
+class ConfigFactory
+{
+ /**
+ * @param Config\ConfigCacheLoader $loader The Config Cache loader (INI/config/.htconfig)
+ *
+ * @return Config\ConfigCache
+ */
+ public static function createCache(Config\ConfigCacheLoader $loader)
+ {
+ $configCache = new Config\ConfigCache();
+ $loader->loadConfigFiles($configCache);
+
+ return $configCache;
+ }
+
+ /**
+ * @param string $type The adapter type
+ * @param Config\IConfigCache $config The config cache of this adapter
+ *
+ * @return Config\IConfigAdapter
+ */
+ public static function createConfig($type, Config\IConfigCache $config)
+ {
+ if ($type == 'preload') {
+ return new Config\PreloadConfigAdapter($config);
+ } else {
+ return new Config\JITConfigAdapter($config);
+ }
+ }
+
+ /**
+ * @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
+ *
+ * @return Config\IPConfigAdapter
+ */
+ public static function createPConfig($type, Config\IPConfigCache $config, $uid = null)
+ {
+ if ($type == 'preload') {
+ return new Config\PreloadPConfigAdapter($config, $uid);
+ } else {
+ return new Config\JITPConfigAdapter($config);
+ }
+ }
+}
--- /dev/null
+<?php
+
+namespace Friendica\Factory;
+
+use Friendica\Core\Config\ConfigCache;
+use Friendica\Network\HTTPException\InternalServerErrorException;
+use Friendica\Util\Logger\FriendicaDevelopHandler;
+use Friendica\Util\Logger\FriendicaIntrospectionProcessor;
+use Monolog;
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+
+/**
+ * A logger factory
+ *
+ * Currently only Monolog is supported
+ */
+class LoggerFactory
+{
+ /**
+ * Creates a new PSR-3 compliant logger instances
+ *
+ * @param string $channel The channel of the logger instance
+ * @param ConfigCache $config The config
+ *
+ * @return LoggerInterface The PSR-3 compliant logger instance
+ */
+ public static function create($channel, ConfigCache $config = 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']));
+
+ if (isset($config)) {
+ $debugging = $config->get('system', 'debugging');
+ $stream = $config->get('system', 'logfile');
+ $level = $config->get('system', 'loglevel');
+
+ if ($debugging) {
+ static::addStreamHandler($logger, $stream, $level);
+ }
+ }
+
+ return $logger;
+ }
+
+ /**
+ * Creates a new PSR-3 compliant develop logger
+ *
+ * If you want to debug only interactions from your IP or the IP of a remote server for federation debug,
+ * you'll use this logger instance for the duration of your work.
+ *
+ * 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
+ *
+ * @return LoggerInterface The PSR-3 compliant logger instance
+ */
+ public static function createDev($channel, $developerIp)
+ {
+ $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));
+
+ return $logger;
+ }
+
+ /**
+ * Adding a handler to a given logger instance
+ *
+ * @param LoggerInterface $logger The logger instance
+ * @param mixed $stream The stream which handles the logger output
+ * @param string $level The level, for which this handler at least should handle logging
+ *
+ * @return void
+ *
+ * @throws InternalServerErrorException if the logger is incompatible to the logger factory
+ * @throws \Exception in case of general failures
+ */
+ public static function addStreamHandler($logger, $stream, $level = LogLevel::NOTICE)
+ {
+ if ($logger instanceof Monolog\Logger) {
+ $loglevel = Monolog\Logger::toMonologLevel($level);
+
+ // fallback to notice if an invalid loglevel is set
+ if (!is_int($loglevel)) {
+ $loglevel = LogLevel::NOTICE;
+ }
+ $fileHandler = new Monolog\Handler\StreamHandler($stream, $loglevel);
+
+ $formatter = new Monolog\Formatter\LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
+ $fileHandler->setFormatter($formatter);
+
+ $logger->pushHandler($fileHandler);
+ } else {
+ throw new InternalServerErrorException('Logger instance incompatible for MonologFactory');
+ }
+ }
+
+ /**
+ * 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)
+ {
+ 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');
+ }
+ }
+}
namespace Friendica\Model;
use Friendica\BaseObject;
-use Friendica\Core\System;
use Friendica\Core\StorageManager;
+use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\Model\Storage\IStorage;
use Friendica\Object\Image;
-use Friendica\Util\Security;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Mimetype;
+use Friendica\Util\Security;
/**
* Class to handle attach dabatase table
*/
private static function getFields()
{
- $allfields = DBStructure::definition(false);
+ $allfields = DBStructure::definition(self::getApp()->getBasePath(), false);
$fields = array_keys($allfields['attach']['fields']);
array_splice($fields, array_search('data', $fields), 1);
return $fields;
return;
}
- self::$installer->installDatabase();
+ self::$installer->installDatabase($a->getBasePath());
break;
}
--- /dev/null
+<?php
+
+namespace Friendica\Util;
+
+class BasePath
+{
+ /**
+ * @brief Returns the base filesystem path of the App
+ *
+ * It first checks for the internal variable, then for DOCUMENT_ROOT and
+ * finally for PWD
+ *
+ * @param string|null $basePath The default base path
+ * @param array $server server arguments
+ *
+ * @return string
+ *
+ * @throws \Exception if directory isn't usable
+ */
+ public static function create($basePath, $server = [])
+ {
+ if (!$basePath && !empty($server['DOCUMENT_ROOT'])) {
+ $basePath = $server['DOCUMENT_ROOT'];
+ }
+
+ if (!$basePath && !empty($server['PWD'])) {
+ $basePath = $server['PWD'];
+ }
+
+ return self::getRealPath($basePath);
+ }
+
+ /**
+ * @brief Returns a normalized file path
+ *
+ * This is a wrapper for the "realpath" function.
+ * That function cannot detect the real path when some folders aren't readable.
+ * Since this could happen with some hosters we need to handle this.
+ *
+ * @param string $path The path that is about to be normalized
+ * @return string normalized path - when possible
+ */
+ public static function getRealPath($path)
+ {
+ $normalized = realpath($path);
+
+ if (!is_bool($normalized)) {
+ return $normalized;
+ } else {
+ return $path;
+ }
+ }
+}
+++ /dev/null
-<?php
-
-namespace Friendica\Util;
-
-use Friendica\Network\HTTPException\InternalServerErrorException;
-use Friendica\Util\Logger\FriendicaDevelopHandler;
-use Friendica\Util\Logger\FriendicaIntrospectionProcessor;
-use Monolog;
-use Psr\Log\LoggerInterface;
-use Psr\Log\LogLevel;
-
-/**
- * A logger factory
- *
- * Currently only Monolog is supported
- */
-class LoggerFactory
-{
- /**
- * Creates a new PSR-3 compliant logger instances
- *
- * @param string $channel The channel of the logger instance
- *
- * @return LoggerInterface The PSR-3 compliant logger instance
- */
- public static function create($channel)
- {
- $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']));
-
- return $logger;
- }
-
- /**
- * Creates a new PSR-3 compliant develop logger
- *
- * If you want to debug only interactions from your IP or the IP of a remote server for federation debug,
- * you'll use this logger instance for the duration of your work.
- *
- * 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
- *
- * @return LoggerInterface The PSR-3 compliant logger instance
- */
- public static function createDev($channel, $developerIp)
- {
- $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));
-
- return $logger;
- }
-
- /**
- * Adding a handler to a given logger instance
- *
- * @param LoggerInterface $logger The logger instance
- * @param mixed $stream The stream which handles the logger output
- * @param string $level The level, for which this handler at least should handle logging
- *
- * @return void
- *
- * @throws InternalServerErrorException if the logger is incompatible to the logger factory
- * @throws \Exception in case of general failures
- */
- public static function addStreamHandler($logger, $stream, $level = LogLevel::NOTICE)
- {
- if ($logger instanceof Monolog\Logger) {
- $loglevel = Monolog\Logger::toMonologLevel($level);
-
- // fallback to notice if an invalid loglevel is set
- if (!is_int($loglevel)) {
- $loglevel = LogLevel::NOTICE;
- }
- $fileHandler = new Monolog\Handler\StreamHandler($stream, $loglevel);
-
- $formatter = new Monolog\Formatter\LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
- $fileHandler->setFormatter($formatter);
-
- $logger->pushHandler($fileHandler);
- } else {
- throw new InternalServerErrorException('Logger instance incompatible for MonologFactory');
- }
- }
-
- /**
- * 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)
- {
- 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');
- }
- }
-}
*/
namespace Friendica\Worker;
+use Friendica\BaseObject;
use Friendica\Core\Update;
-class DBUpdate
+class DBUpdate extends BaseObject
{
public static function execute()
{
- Update::run();
+ Update::run(self::getApp()->getBasePath());
}
}
namespace Friendica\Test;
+use Friendica\Core\Config;
use Friendica\Database\DBA;
+use Friendica\Factory;
+use Friendica\Util\BasePath;
use PHPUnit\DbUnit\DataSet\YamlDataSet;
use PHPUnit\DbUnit\TestCaseTrait;
use PHPUnit_Extensions_Database_DB_IDatabaseConnection;
$this->markTestSkipped('Please set the MYSQL_* environment variables to your test database credentials.');
}
- DBA::connect(getenv('MYSQL_HOST'),
+ $basedir = BasePath::create(dirname(__DIR__));
+ $configLoader = new Config\ConfigCacheLoader($basedir);
+ $config = Factory\ConfigFactory::createCache($configLoader);
+
+ DBA::connect(
+ $config,
+ getenv('MYSQL_HOST'),
getenv('MYSQL_USERNAME'),
getenv('MYSQL_PASSWORD'),
getenv('MYSQL_DATABASE'));
use Friendica\App;
use Friendica\BaseObject;
+use Friendica\Core\Config\ConfigCache;
use Friendica\Render\FriendicaSmartyEngine;
use Mockery\MockInterface;
use org\bovigo\vfs\vfsStreamDirectory;
* Mock the App
*
* @param vfsStreamDirectory $root The root directory
+ * @param MockInterface|ConfigCache $config The config cache
*/
- public function mockApp($root)
+ public function mockApp($root, $config)
{
$this->mockConfigGet('system', 'theme', 'testtheme');
->shouldReceive('getBasePath')
->andReturn($root->url());
- $this->app
- ->shouldReceive('getConfigValue')
+ $config
+ ->shouldReceive('get')
->with('database', 'hostname')
->andReturn(getenv('MYSQL_HOST'));
- $this->app
- ->shouldReceive('getConfigValue')
+ $config
+ ->shouldReceive('get')
->with('database', 'username')
->andReturn(getenv('MYSQL_USERNAME'));
- $this->app
- ->shouldReceive('getConfigValue')
+ $config
+ ->shouldReceive('get')
->with('database', 'password')
->andReturn(getenv('MYSQL_PASSWORD'));
- $this->app
- ->shouldReceive('getConfigValue')
+ $config
+ ->shouldReceive('get')
->with('database', 'database')
->andReturn(getenv('MYSQL_DATABASE'));
+ $this->app
+ ->shouldReceive('getConfig')
+ ->andReturn($config);
+
$this->app
->shouldReceive('getTemplateEngine')
->andReturn(new FriendicaSmartyEngine());
namespace Friendica\Test;
-use Friendica\BaseObject;
+use Friendica\App;
use Friendica\Core\Config;
use Friendica\Core\PConfig;
use Friendica\Core\Protocol;
use Friendica\Core\System;
+use Friendica\Factory;
use Friendica\Network\HTTPException;
-use Friendica\Util\LoggerFactory;
+use Friendica\Util\BasePath;
use Monolog\Handler\TestHandler;
require_once __DIR__ . '/../../include/api.php';
*/
public function setUp()
{
- parent::setUp();
+ $basedir = BasePath::create(dirname(__DIR__) . '/../');
+ $configLoader = new Config\ConfigCacheLoader($basedir);
+ $config = Factory\ConfigFactory::createCache($configLoader);
+ $logger = Factory\LoggerFactory::create('test', $config);
+ $this->app = new App($config, $logger, false);
+ $this->logOutput = FActory\LoggerFactory::enableTest($this->app->getLogger());
- $this->app = BaseObject::getApp();
- $this->logOutput = LoggerFactory::enableTest($this->app->getLogger());
+ parent::setUp();
// User data that the test database is populated with
$this->selfUser = [
*/
protected function setUp()
{
- $this->setUpVfsDir();
- $this->mockApp($this->root);
-
$this->baseObject = new BaseObject();
}
*/
public function testGetApp()
{
+ $this->setUpVfsDir();
+ $configMock = \Mockery::mock('Friendica\Core\Config\ConfigCache');
+ $this->mockApp($this->root, $configMock);
+
$this->assertInstanceOf(App::class, $this->baseObject->getApp());
}
*/
public function testSetApp()
{
+ $this->setUpVfsDir();
+ $configMock = \Mockery::mock('Friendica\Core\Config\ConfigCache');
+ $this->mockApp($this->root, $configMock);
+
$this->assertNull($this->baseObject->setApp($this->app));
$this->assertEquals($this->app, $this->baseObject->getApp());
}
+
+ /**
+ * Test the getApp() function without App
+ * @expectedException Friendica\Network\HTTPException\InternalServerErrorException
+ */
+ public function testGetAppFailed()
+ {
+ BaseObject::getApp();
+ }
}
protected function setUp()
{
$this->setUpVfsDir();
- $this->mockApp($this->root);
+ $configMock = \Mockery::mock('Friendica\Core\Config\ConfigCache');
+ $this->mockApp($this->root, $configMock);
$this->app
->shouldReceive('getHostname')
->andReturn('friendica.local');
$this->mockConnect(true, 1);
$this->mockConnected(true, 1);
$this->mockExistsTable('user', false, 1);
- $this->mockUpdate([false, true, true], null, 1);
+ $this->mockUpdate([$this->root->url(), false, true, true], null, 1);
$config = <<<CONF
<?php
$this->mockConnect(true, 1);
$this->mockConnected(true, 1);
$this->mockExistsTable('user', false, 1);
- $this->mockUpdate([false, true, true], null, 1);
+ $this->mockUpdate([$this->root->url(), false, true, true], null, 1);
$this->mockGetMarkupTemplate('local.config.tpl', 'testTemplate', 1);
$this->mockReplaceMacros('testTemplate', $this->createArgumentsForMacro(true), '', 1);
$this->mockConnect(true, 1);
$this->mockConnected(true, 1);
$this->mockExistsTable('user', false, 1);
- $this->mockUpdate([false, true, true], null, 1);
+ $this->mockUpdate([$this->root->url(), false, true, true], null, 1);
$this->mockGetMarkupTemplate('local.config.tpl', 'testTemplate', 1);
$this->mockReplaceMacros('testTemplate', $this->createArgumentsForMacro(false), '', 1);
$this->mockConnect(true, 1);
$this->mockConnected(true, 1);
$this->mockExistsTable('user', false, 1);
- $this->mockUpdate([false, true, true], null, 1);
+ $this->mockUpdate([$this->root->url(), false, true, true], null, 1);
$this->mockGetMarkupTemplate('local.config.tpl', 'testTemplate', 1);
$this->mockReplaceMacros('testTemplate', $this->createArgumentsForMacro(true), '', 1);
Intercept::setUp();
$this->setUpVfsDir();
- $this->mockApp($this->root);
+ $configMock = \Mockery::mock('Friendica\Core\Config\ConfigCache');
+ $this->mockApp($this->root, $configMock);
}
/**
// Reusable App object
$this->setUpVfsDir();
- $this->mockApp($this->root);
+ $configMock = \Mockery::mock('Friendica\Core\Config\ConfigCache');
+ $this->mockApp($this->root, $configMock);
$this->app
->shouldReceive('getHostname')
->andReturn('friendica.local');
<?php
namespace Friendica\Test\Database;
-use Friendica\BaseObject;
+use Friendica\App;
use Friendica\Core\Config;
use Friendica\Database\DBA;
+use Friendica\Factory;
use Friendica\Test\DatabaseTest;
+use Friendica\Util\BasePath;
class DBATest extends DatabaseTest
{
public function setUp()
{
- parent::setUp();
+ $basedir = BasePath::create(dirname(__DIR__) . '/../../');
+ $configLoader = new Config\ConfigCacheLoader($basedir);
+ $config = Factory\ConfigFactory::createCache($configLoader);
+ $logger = Factory\LoggerFactory::create('test', $config);
+ $this->app = new App($config, $logger, false);
+ $this->logOutput = FActory\LoggerFactory::enableTest($this->app->getLogger());
- // Reusable App object
- $this->app = BaseObject::getApp();
+ parent::setUp();
// Default config
Config::set('config', 'hostname', 'localhost');
namespace Friendica\Test\Database;
-use Friendica\BaseObject;
+use Friendica\App;
use Friendica\Core\Config;
use Friendica\Database\DBStructure;
+use Friendica\Factory;
use Friendica\Test\DatabaseTest;
+use Friendica\Util\BasePath;
class DBStructureTest extends DatabaseTest
{
public function setUp()
{
- parent::setUp();
+ $basedir = BasePath::create(dirname(__DIR__) . '/../../');
+ $configLoader = new Config\ConfigCacheLoader($basedir);
+ $config = Factory\ConfigFactory::createCache($configLoader);
+ $logger = Factory\LoggerFactory::create('test', $config);
+ $this->app = new App($config, $logger, false);
+ $this->logOutput = FActory\LoggerFactory::enableTest($this->app->getLogger());
- // Reusable App object
- $this->app = BaseObject::getApp();
+ parent::setUp();
// Default config
Config::set('config', 'hostname', 'localhost');
.wall-item-bottom .label a {
color: #fff;
}
+.wall-item-tags .category,
+.wall-item-tags .folder {
+ margin-right: 3px;
+}
/* item social action buttons */
.wall-item-actions {
{{/if}}
{{foreach $item.folders as $cat}}
- <span class="folder label btn-danger sm">{{$cat.name}}</a>{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
+ <span class="folder label btn-danger sm">{{$cat.name}}{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
{{/foreach}}
{{foreach $item.categories as $cat}}
- <span class="category label btn-success sm">{{$cat.name}}</a>{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
+ <span class="category label btn-success sm">{{$cat.name}}{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
{{/foreach}}
</div>
{{if $item.edited}}<div class="itemedited text-muted">{{$item.edited['label']}} (<span title="{{$item.edited['date']}}">{{$item.edited['relative']}}</span>)</div>{{/if}}
{{/if}}
{{foreach $item.folders as $cat}}
- <span class="folder label btn-danger sm"><span class="p-category">{{$cat.name}}</span></a>{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
+ <span class="folder label btn-danger sm p-category">{{$cat.name}}{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
{{/foreach}}
{{foreach $item.categories as $cat}}
- <span class="category label btn-success sm"><span class="p-category">{{$cat.name}}</span></a>{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
+ <span class="category label btn-success sm p-category">{{$cat.name}}{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
{{/foreach}}
</div>
{{if $item.edited}}<div class="itemedited text-muted">{{$item.edited['label']}} (<span title="{{$item.edited['date']}}">{{$item.edited['relative']}}</span>)</div>{{/if}}