/** * Loads the configuration and plugins in the right order * @method configure * @static * @param boolean [$force_reload=false] If true, forces the reload of the cache. * Otherwise it happens only if Q/configServer/interval seconds * have passed since the last time. * @throws {Q_Exception_MissingPlugin} */ static function configure($force_reload = false) { $app_tree = new Q_Tree(); // check if config need to be reloaded if (Q_Cache::connected()) { // we need to know reload interval $app_tree->load('config/Q.json'); $app_tree->load('config/app.json'); $app_tree->load('local/app.json'); $config_files = $app_tree->get('Q', 'configFiles', array()); foreach ($config_files as $cf) { $app_tree->merge(Q_Config::getFromServer($cf)); } // second round to catch configFiles inside configFiles $config_files = $app_tree->get('Q', 'configFiles', array()); foreach ($config_files as $cf) { $app_tree->merge(Q_Config::getFromServer($cf)); } $interval = $app_tree->get('Q', 'configServer', 'interval', 60); // reload each minute by default $app_tree->clear(null); $timestamp = Q_Cache::get("Q_Config\tupdate_time"); if (!isset($timestamp) || time() - $timestamp > $interval) { $force_reload = true; } } if ($force_reload) { $old_setting = Q_Cache::ignore(true); } Q_Config::clear(null); // clear the config Q_Config::load('config/Q.json'); // Get the app config, but don't load it yet $app_tree->load('config/app.json'); $app_tree->load('local/app.json'); // Load all the plugin config files first $paths = explode(PS, get_include_path()); $plugins = $app_tree->get('Q', 'plugins', array()); if (!in_array('Q', $plugins)) { array_unshift($plugins, 'Q'); } global $Q_Bootstrap_config_plugin_limit; $i = 0; foreach ($plugins as $k => $v) { ++$i; if (isset($Q_Bootstrap_config_plugin_limit) and $i > $Q_Bootstrap_config_plugin_limit) { continue; } $plugin = is_numeric($k) ? $v : $k; $plugin_path = Q::realPath('plugins' . DS . $v); if (!$plugin_path) { throw new Q_Exception_MissingPlugin(compact('plugin')); } Q_Config::load($plugin_path . DS . 'config' . DS . 'plugin.json'); array_splice($paths, 1, 0, array($plugin_path)); $PLUGIN = strtoupper($plugin); if (!defined($PLUGIN . '_PLUGIN_DIR')) { define($PLUGIN . '_PLUGIN_DIR', $plugin_path); } if (!defined($PLUGIN . '_PLUGIN_CONFIG_DIR')) { define($PLUGIN . '_PLUGIN_CONFIG_DIR', $plugin_path . DS . 'config'); } if (!defined($PLUGIN . '_PLUGIN_CLASSES_DIR')) { define($PLUGIN . '_PLUGIN_CLASSES_DIR', $plugin_path . DS . 'classes'); } if (!defined($PLUGIN . '_PLUGIN_FILES_DIR')) { define($PLUGIN . '_PLUGIN_FILES_DIR', $plugin_path . DS . 'files'); } if (!defined($PLUGIN . '_PLUGIN_HANDLERS_DIR')) { define($PLUGIN . '_PLUGIN_HANDLERS_DIR', $plugin_path . DS . 'handlers'); } if (!defined($PLUGIN . '_PLUGIN_PLUGINS_DIR')) { define($PLUGIN . '_PLUGIN_PLUGINS_DIR', $plugin_path . DS . 'plugins'); } if (!defined($PLUGIN . '_PLUGIN_SCRIPTS_DIR')) { define($PLUGIN . '_PLUGIN_SCRIPTS_DIR', $plugin_path . DS . 'scripts'); } if (!defined($PLUGIN . '_PLUGIN_VIEWS_DIR')) { define($PLUGIN . '_PLUGIN_VIEWS_DIR', $plugin_path . DS . 'views'); } if (!defined($PLUGIN . '_PLUGIN_TESTS_DIR')) { define($PLUGIN . '_PLUGIN_TESTS_DIR', $plugin_path . DS . 'tests'); } if (!defined($PLUGIN . '_PLUGIN_WEB_DIR')) { define($PLUGIN . '_PLUGIN_WEB_DIR', $plugin_path . DS . 'web'); } self::$plugins[$plugin] = $plugin_path; } $paths = array_unique($paths); set_include_path(implode(PS, $paths)); // Now, we can merge in our app's config Q_Config::merge($app_tree); // Now, load any other files we were supposed to load $config_files = Q_Config::get('Q', 'configFiles', array()); foreach ($config_files as $cf) { Q_Config::merge(Q_Config::getFromServer($cf)); } // second round to catch configFiles inside configFiles $config_files = Q_Config::get('Q', 'configFiles', array()); foreach ($config_files as $cf) { Q_Config::merge(Q_Config::getFromServer($cf)); } $script_files = Q_Config::get('Q', 'scriptFiles', array()); foreach ($script_files as $cf) { Q::includeFile($cf); } error_reporting(Q_Config::get('Q', 'errorReporting', E_ALL)); if (isset($old_setting)) { Q_Cache::ignore($old_setting); } set_time_limit(Q_Config::get('Q', 'internal', 'phpTimeout', 30)); self::setDefaultTimezone(); }
/** * @method installPlugin * @static * @param {string} $plugin_name * @param {array} $options * @throws {Exception} */ static function installPlugin($plugin_name, $options) { set_time_limit(Q_Config::expect('Q', 'install', 'timeLimit')); // Connect Qbix platform if it's not already connected self::prepare(); $app_dir = APP_DIR; $plugin_dir = Q_PLUGINS_DIR . DS . $plugin_name; $app_web_plugins_dir = APP_WEB_DIR . DS . 'plugins'; echo "Installing plugin '{$plugin_name}' into '{$app_dir}'" . PHP_EOL; // Do we even have such a plugin? if (!is_dir($plugin_dir)) { throw new Exception("Plugin '{$plugin_name}' not found in " . Q_PLUGINS_DIR); } // Ensure that the plugin has config.json if (!file_exists($plugin_conf_file = $plugin_dir . DS . 'config' . DS . 'plugin.json')) { throw new Exception("Could not load plugin's config. Check {$plugin_conf_file}"); } $files_dir = $plugin_dir . DS . 'files'; $app_plugins_file = APP_LOCAL_DIR . DS . 'plugins.json'; // Check access to $app_web_plugins_dir if (!file_exists($app_web_plugins_dir)) { if (!@mkdir($app_web_plugins_dir, 0755, true)) { throw new Exception("Could not create {$app_web_plugins_dir}"); } } if (!is_dir($app_web_plugins_dir)) { throw new Exception("{$app_web_plugins_dir} exists, but is not a directory"); } elseif (!is_writable($app_web_plugins_dir)) { throw new Exception("Can not write to {$app_web_plugins_dir}"); } // Check access to $app_plugins_file if (file_exists($app_plugins_file) && !is_writable($app_plugins_file)) { throw new Exception("Can not write to {$app_plugins_file}"); } elseif (!file_exists($app_plugins_file) && !is_writable(dirname($app_plugins_file))) { throw new Exception("Can not write to " . dirname($app_plugins_file)); } // Check access to $files_dir if (!file_exists($files_dir)) { if (!@mkdir($files_dir, $options['dirmode'], true)) { throw new Exception("Could not create {$files_dir}"); } } // Do we now have plugin's config? if (Q_Config::get('Q', 'pluginInfo', $plugin_name, 'version', null) == null) { throw new Exception("Could not identify plugin version. Check {$plugin_conf_file}"); } $plugin_conf = Q_Config::get('Q', 'pluginInfo', $plugin_name, null); $plugin_version = $plugin_conf['version']; if (file_exists($app_plugins_file)) { Q_Config::load($app_plugins_file, true); } // Do we already have this plugin installed for this app? // Check requirements for plugin (will throw exceptions if they aren't met) if (!isset($options['noreq']) || !$options['noreq']) { echo "Checking requirements" . PHP_EOL; Q_Bootstrap::checkRequirements(array($plugin_name)); } // Checking LOCAL plugin version in plugins.json file if (($version_installed = Q_Config::get('Q', 'pluginLocal', $plugin_name, 'version', null)) != null) { //We have this plugin installed echo "Plugin '{$plugin_name}' (version: {$version_installed}) is already installed" . PHP_EOL; if (Q::compare_version($version_installed, $plugin_version) < 0) { echo "Upgrading '{$plugin_name}' to version: {$plugin_version}" . PHP_EOL; } } // Check and fix permissions self::checkPermissions($files_dir, $options); if (isset($plugin_conf['permissions'])) { foreach ($plugin_conf['permissions'] as $perm) { self::checkPermissions($files_dir . DS . $perm, $options); } } // Symbolic links echo 'Creating symbolic links' . PHP_EOL; self::symlink($plugin_dir . DS . 'web', $app_web_plugins_dir . DS . $plugin_name); // Checking if schema update is requested and updating database version $connections = Q_Config::get('Q', 'pluginInfo', $plugin_name, 'connections', array()); foreach ($connections as $connection) { self::installSchema(Q_PLUGINS_DIR . DS . $plugin_name, $plugin_name, 'plugin', $connection, $options); } // Push plugin name into Q/plugins array if (!in_array($plugin_name, $current_plugins = Q_Config::get('Q', 'plugins', array()))) { $current_plugins[] = $plugin_name; Q_Config::set('Q', 'plugins', $current_plugins); //TODO: When do we save Q/plugins to disk? } // Save info about plugin echo 'Registering plugin' . PHP_EOL; Q_Config::set('Q', 'pluginLocal', $plugin_name, $plugin_conf); Q_Config::save($app_plugins_file, array('Q', 'pluginLocal')); echo Q_Utils::colored("Plugin '{$plugin_name}' successfully installed" . PHP_EOL, 'green'); }