/** * @constructor * @param {array} [$options=array()] Any initial options * @param {Users_User} [$options.user=Users::loggedInUser()] Allows us to set the user to charge * @param {string} [$options.authname] Optionally override the authname from config * @param {string} [$options.authkey] Optionally override the authkey from config */ function __construct($options = array()) { Q::includeFile(implode(DS, array(Q_PLUGINS_DIR, 'Assets', 'classes', 'Composer', 'vendor', 'autoload.php'))); $testing = Q_Config::expect('Assets', 'payments', 'authnet', 'testing'); $server = $testing ? net\authorize\api\constants\ANetEnvironment::SANDBOX : net\authorize\api\constants\ANetEnvironment::PRODUCTION; if (!isset($options['user'])) { $options['user'] = Users::loggedInUser(true); } $this->options = array_merge(array('authname' => Q_Config::expect('Assets', 'payments', 'authnet', 'name'), 'authkey' => Q_Config::expect('Assets', 'payments', 'authnet', 'transactionKey'), 'server' => $server), $options); }
/** * Returns a <style> tag with the content of all the stylesheets included inline * @method stylesheetsInline * @static * @param {array} [$styles=array()] If not empty, this associative array contains styles which will be * included at the end of the generated <style> tag. * @param {string} [$slotName=null] If provided, returns only the stylesheets added while filling this slot. * @return {string} the style tags and their contents inline */ static function stylesheetsInline($styles = array(), $slotName = null) { if (empty(self::$stylesheets)) { return ''; } $sheets = self::stylesheetsArray($slotName, false); $sheets_for_slots = array(); if (!empty($sheets)) { foreach ($sheets as $stylesheet) { $href = ''; $media = 'screen, print'; $type = 'text/css'; extract($stylesheet, EXTR_IF_EXISTS); $ob = new Q_OutputBuffer(); if (Q_Valid::url($href)) { try { include $href; } catch (Exception $e) { } } else { list($href, $filename) = Q_Html::themedUrlAndFilename($href); try { Q::includeFile($filename); } catch (Exception $e) { } } $sheets_for_slots[$stylesheet['slot']][] = "\n/* Included inline from {$href} */\n" . $ob->getClean(); } } $parts = array(); foreach ($sheets_for_slots as $slot => $texts) { $parts[] = Q_Html::tag('style', array('data-slot' => $slot), implode("\n\n", $texts)); } return implode("", $parts); }
/** * 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(); }
/** * Install or update schema for app or plugin * @method installSchema * @static * @param {string} $base_dir The directory where application or plugin is located * @param {string} $name The name of application or plugin * @param {string} $type One of 'app' or 'plugin' * @param {string} $conn_name The name of the connection to affect * @param {string} $options Contain data parsed from command line * @throws {Exception} If cannot connect to database */ static function installSchema($base_dir, $name, $type, $conn_name, $options) { // is schema installation requested? if (!isset($options['sql']) || empty($options['sql'][$conn_name]) || !$options['sql'][$conn_name]['enabled']) { return; } $config = $type === 'app' ? Q_Config::get('Q', "{$type}Info", null) : Q_Config::get('Q', "{$type}Info", $name, null); // version to install or update $version = $config['version']; // Get SQL connection for currently installed schema // Is schema connection information provided? if (($dbconf = Db::getConnection($conn_name)) == null) { throw new Exception("Could not get info for database connection '{$conn_name}'. Check " . APP_LOCAL_DIR . "/app.json"); } // If option -sql-user-pass was used, override config's username and password // TODO: set pasword per shard if (isset($options['sql'][$conn_name]['username'])) { $dbconf['username'] = $options['sql'][$conn_name]['username']; $dbconf['password'] = self::getPassword($conn_name); } $shards = array('' => $dbconf); if (isset($dbconf['shards'])) { $shards = array_merge($shards, $dbconf['shards']); } foreach ($shards as $shard => $data) { $shard_text = $shard === '' ? "" : " shard '{$shard}'"; $tempname = $conn_name . '_' . time(); $shard_data = array_merge($dbconf, $data); Db::setConnection($tempname, $shard_data); // Try connecting try { $db = Db::connect($tempname); $pdo = $db->reallyConnect($shard); list($dbms) = explode(':', $shard_data['dsn']); $prefix = $shard_data['prefix']; } catch (Exception $e) { throw new Exception("Could not connect to DB connection '{$conn_name}'{$shard_text}: " . $e->getMessage(), $e->getCode(), $e); } $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true); // Do we already have $name installed? // Checking SCHEMA plugin version in the DB. $db->rawQuery("CREATE TABLE IF NOT EXISTS `{$prefix}Q_{$type}` (\n\t\t\t\t`{$type}` VARCHAR(255) NOT NULL,\n\t\t\t\t`version` VARCHAR( 255 ) NOT NULL,\n\t\t\t\tPRIMARY KEY (`{$type}`)) ENGINE = InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;\n\t\t\t")->execute(); $res = $db->select('version', "{$prefix}Q_{$type}")->where(array($type => $name))->fetchAll(PDO::FETCH_ASSOC); // If we have version in the db then this is upgrade if (!empty($res)) { $current_version = $res[0]['version']; echo ucfirst($type) . " '{$name}' schema on '{$conn_name}'{$shard_text} (v. {$current_version}) is already installed" . PHP_EOL; if (Q::compare_version($current_version, $version) < 0) { echo "Upgrading '{$name}' on '{$conn_name}'{$shard_text} schema to version: {$version}" . PHP_EOL; } else { continue; } } else { // Otherwise considering that plugin has version '0' to override it for getSqlScripts() $current_version = 0; } // collect script files for upgrade $scriptsdir = $base_dir . DS . 'scripts' . DS . $name; $scripts = array(); if (!is_dir($scriptsdir)) { return; } $dir = opendir($scriptsdir); // Find all scripts for this dbms while (($entry = readdir($dir)) !== false) { $parts = preg_split('/(-|__)/', $entry, 2); // wrong filename format if (count($parts) < 2) { continue; } list($sqlver, $tail) = $parts; if ($tail !== "{$conn_name}.{$dbms}" and $tail !== "{$conn_name}.{$dbms}.php") { continue; // not schema file or php script } // If this sql file is for earlier or same plugin version than installed - skip it // If this sql file is for later plugin version than we are installing - skip it if (Q::compare_version($sqlver, $current_version) <= 0 || Q::compare_version($sqlver, $version) > 0) { continue; } // we shall install this script! if ($tail !== "{$conn_name}.{$dbms}.php") { $scripts[$sqlver] = $entry; } else { $scripts["{$sqlver}.php"] = $entry; } } closedir($dir); // Sort scripts according to version uksort($scripts, array('Q', 'compare_version')); if (!empty($scripts)) { echo "Running SQL scripts for {$type} {$name} on {$conn_name} ({$dbms})" . PHP_EOL; } // echo "Begin transaction".PHP_EOL; // $query = $db->rawQuery('')->begin()->execute(); // Process script files foreach ($scripts as $script) { try { if (substr($script, -4) === '.php') { echo "Processing PHP file: {$script} \n"; Q::includeFile($scriptsdir . DS . $script); continue; } echo "Processing SQL file: {$script} "; $sqltext = file_get_contents($scriptsdir . DS . $script); $sqltext = str_replace('{$prefix}', $prefix, $sqltext); $sqltext = str_replace('{$dbname}', $db->dbname, $sqltext); $queries = $db->scriptToQueries($sqltext); // Process each query foreach ($queries as $q) { $db->rawQuery($q)->execute(); echo "."; } // Update plugin db version if ($dbms === 'mysql') { list($newver) = preg_split('/(-|__)/', $script, 2); $db->insert("{$prefix}Q_{$type}", array($type => $name, 'version' => $newver))->onDuplicateKeyUpdate(array('version' => $newver))->execute(); $current_version = $newver; } echo PHP_EOL; } catch (Exception $e) { $errorCode = $pdo->errorCode(); if ($errorCode != '00000') { $info = $pdo->errorInfo(); $err = new Q_Exception("{$info['2']}", array(), $errorCode, $e->getFile(), $e->getLine(), $e->getTrace(), $e->getTraceAsString()); } else { $err = $e; } throw $err; // echo PHP_EOL; // echo "Rollback".PHP_EOL; // try { // $query = $db->rawQuery('')->rollback()->execute(); // } catch (Exception $e) { // throw $err; // } } } try { if (Q::compare_version($version, $current_version) > 0) { $db->insert("{$prefix}Q_{$type}", array($type => $name, 'version' => $version))->onDuplicateKeyUpdate(array('version' => $version))->execute(); } } catch (Exception $e) { if ($pdo->errorCode() != '00000') { // echo "Rollback".PHP_EOL; // $query = $db->rawQuery('')->rollback()->execute(); // $err = $pdo->errorInfo(); throw new Exception("{$err['2']}"); } } // echo "Commit transaction".PHP_EOL; // $query = $db->rawQuery('')->commit()->execute(); echo '+ ' . ucfirst($type) . " '{$name}' schema on '{$conn_name}'{$shard_text} (v. {$current_version} -> {$version}) installed" . PHP_EOL; } }