/** * Parse all callbacks and builds the tree. * * @param integer $user ID of the user for which the profile is displayed. * @param bool $iscurrentuser true if the profile being viewed is of current user, else false. * @param \stdClass $course Course object * * @return tree Fully build tree to be rendered on my profile page. */ public static function build_tree($user, $iscurrentuser, $course = null) { global $CFG; $tree = new tree(); // Add core nodes. require_once $CFG->libdir . "/myprofilelib.php"; core_myprofile_navigation($tree, $user, $iscurrentuser, $course); // Core components. $components = \core_component::get_core_subsystems(); foreach ($components as $component => $directory) { if (empty($directory)) { continue; } $file = $directory . "/lib.php"; if (is_readable($file)) { require_once $file; $function = "core_" . $component . "_myprofile_navigation"; if (function_exists($function)) { $function($tree, $user, $iscurrentuser, $course); } } } // Plugins. $types = \core_component::get_plugin_types(); foreach ($types as $type => $dir) { $pluginlist = get_plugin_list_with_function($type, "myprofile_navigation", "lib.php"); foreach ($pluginlist as $function) { $function($tree, $user, $iscurrentuser, $course); } } $tree->sort_categories(); return $tree; }
/** * Get the relative path for a plugin given it's type * * @param string $type * The plugin type (example: 'auth', 'block') * @param string $moodleversion * The version of moodle we are running (example: '1.9', '2.9') * @return string * The installation path relative to dirroot (example: 'auth', 'blocks', * 'course/format') */ private function get_install_path($type, $moodleversion) { global $CFG; // Convert moodle version to a float for more acurate comparison if (!is_float($moodleversion)) { $moodleversion = floatval($moodleversion); } if ($moodleversion >= 2.6) { $types = \core_component::get_plugin_types(); } else { if ($moodleversion >= 2.0) { $types = get_plugin_types(); } else { // Moodle 1.9 does not give us a way to determine plugin // installation paths. $types = array(); } } if (empty($types) || !array_key_exists($type, $types)) { // Either the moodle version is lower than 2.0, in which case we // don't have a reliable way of determining the install path, or the // plugin is of an unknown type. // // Let's fall back to make our best guess. return $CFG->dirroot . '/' . $type; } return $types[$type]; }
/** * Get the absolute install directory path within Moodle. * * @param string $component Moodle component, EG: mod_forum * * @return string Absolute path, EG: /path/to/mod/forum */ public function getComponentInstallDirectory($component) { $this->requireConfig(); /* @noinspection PhpUndefinedClassInspection */ list($type, $name) = \core_component::normalize_component($component); /* @noinspection PhpUndefinedClassInspection */ $types = \core_component::get_plugin_types(); if (!array_key_exists($type, $types)) { throw new \InvalidArgumentException(sprintf('The component %s has an unknown plugin type of %s', $component, $type)); } return $types[$type] . '/' . $name; }
public function run($command) { global $CFG; $data = $CFG->dataroot . '/tool_composer'; $composerfile = $data . '/composer.json'; if (!is_writable($data)) { throw new \moodle_exception('notwritable'); } if (!file_exists($data)) { mkdir($data, $CFG->directorypermissions, true); } $vendordir = $data . '/vendor'; $autoloadphp = '$CFG->dataroot . \'tool_composer/vendor/autoload.php\''; if ($this->installincodebase) { $vendordir = $CFG->dirroot . '/lib/vendor'; $autoloadphp = '$CFG->dirroot . \'/lib/vendor/autoload.php\''; } $composer = new \stdClass(); $composer->require = ['wikimedia/composer-merge-plugin' => '^1.3']; $include = []; foreach (\core_component::get_plugin_types() as $type => $dir) { $plugins = \core_component::get_plugin_list_with_file($type, 'composer.json'); foreach ($plugins as $pluginname => $filepath) { // Ignore this plugin if ($type == 'tool' && $pluginname == 'composer') { continue; } $include[] = $filepath; // Overwrite the autoload files if necessary $autoload = dirname($filepath) . '/vendor/autoload.php'; if (file_exists($autoload)) { if (!is_writable($autoload)) { throw new \moodle_exception('notwritable'); } // Back up the file if we haven't done so already. if (!file_exists($autoload . '.bak')) { file_put_contents($autoload . '.bak', file_get_contents($autoload)); } file_put_contents($autoload, '<?php require_once ' . $autoloadphp . ';'); } } } $composer->extra = (object) ['merge-plugin' => (object) ['include' => $include]]; file_put_contents($composerfile, json_encode($composer)); putenv('COMPOSER=' . $composerfile); putenv('COMPOSER_VENDOR_DIR=' . $vendordir); if ($this->installincodebase) { // Allow us to install Moodle plugins into the codebase chdir($CFG->dirroot); } // TODO: We may want to force --no-dev here for install / update passthru('composer --no-interaction ' . $command); }
/** * Get a list of services available in this Moodle installation. * * @return array plugin name => array('name' => '\class\implementing\service') */ public static function service_list() { global $CFG; $result = array(); foreach (\core_component::get_plugin_types() as $plugintype => $fulldir) { foreach (\core_component::get_plugin_list($plugintype) as $name => $dir) { $frankenstyle = $plugintype . '_' . $name; if ($services = self::get_services($frankenstyle)) { $result[$frankenstyle] = $services; } } } return $result; }
/** * Returns all the plugins having tests * @param string $testtype The kind of test we are looking for * @return array all the plugins having tests */ private static function get_all_plugins_with_tests($testtype) { $pluginswithtests = array(); $plugintypes = core_component::get_plugin_types(); ksort($plugintypes); foreach ($plugintypes as $type => $unused) { $plugs = core_component::get_plugin_list($type); ksort($plugs); foreach ($plugs as $plug => $fullplug) { // Look for tests recursively if (self::directory_has_tests($fullplug, $testtype)) { $pluginswithtests[$type . '_' . $plug] = $fullplug; } } } return $pluginswithtests; }
/** * Returns a list of all components installed on the server * * @return array (string)legacyname => (string)frankenstylename */ public static function list_components() { $list['moodle'] = 'core'; $coresubsystems = core_component::get_core_subsystems(); ksort($coresubsystems); // should be but just in case foreach ($coresubsystems as $name => $location) { $list[$name] = 'core_' . $name; } $plugintypes = core_component::get_plugin_types(); foreach ($plugintypes as $type => $location) { $pluginlist = core_component::get_plugin_list($type); foreach ($pluginlist as $name => $ununsed) { if ($type == 'mod') { // Plugin names are now automatically validated. $list[$name] = $type . '_' . $name; } else { $list[$type . '_' . $name] = $type . '_' . $name; } } } return $list; }
/** * Constructor. * @param string $component the component from version.php * @param string $expected expected directory, null means calculate * @param string $current plugin directory path */ public function __construct($component, $expected, $current) { global $CFG; if (empty($expected)) { list($type, $plugin) = core_component::normalize_component($component); $plugintypes = core_component::get_plugin_types(); if (isset($plugintypes[$type])) { $expected = $plugintypes[$type] . '/' . $plugin; } } if (strpos($expected, '$CFG->dirroot') !== 0) { $expected = str_replace($CFG->dirroot, '$CFG->dirroot', $expected); } if (strpos($current, '$CFG->dirroot') !== 0) { $current = str_replace($CFG->dirroot, '$CFG->dirroot', $current); } $a = new stdClass(); $a->component = $component; $a->expected = $expected; $a->current = $current; parent::__construct('detectedmisplacedplugin', 'core_plugin', "$CFG->wwwroot/$CFG->admin/index.php", $a); }
/** * Locates all of the definition files. * * @param bool $coreonly If set to true only core definitions will be updated. * @return array */ protected static function locate_definitions($coreonly = false) { global $CFG; $files = array(); if (file_exists($CFG->dirroot . '/lib/db/caches.php')) { $files['core'] = $CFG->dirroot . '/lib/db/caches.php'; } if (!$coreonly) { $plugintypes = core_component::get_plugin_types(); foreach ($plugintypes as $type => $location) { $plugins = core_component::get_plugin_list_with_file($type, 'db/caches.php'); foreach ($plugins as $plugin => $filepath) { $component = clean_param($type . '_' . $plugin, PARAM_COMPONENT); // Standardised plugin name. $files[$component] = $filepath; } } } $definitions = array(); foreach ($files as $component => $file) { $filedefs = self::load_caches_file($file); foreach ($filedefs as $area => $definition) { $area = clean_param($area, PARAM_AREA); $id = $component . '/' . $area; $definition['component'] = $component; $definition['area'] = $area; if (array_key_exists($id, $definitions)) { debugging('Error: duplicate cache definition found with id: ' . $id, DEBUG_DEVELOPER); continue; } $definitions[$id] = $definition; } } return $definitions; }
/** * Lists all plugin types. * * @deprecated since 2.6, use core_component::get_plugin_types() * * @param bool $fullpaths false means relative paths from dirroot * @return array Array of strings - name=>location */ function get_plugin_types($fullpaths = true) { global $CFG; // NOTE: do not add any other debugging here, keep forever. $types = core_component::get_plugin_types(); if ($fullpaths) { return $types; } debugging('Short paths are deprecated when using get_plugin_types(), please fix the code to use fullpaths instead.', DEBUG_DEVELOPER); $dlength = strlen($CFG->dirroot); foreach ($types as $k => $v) { if ($k === 'theme') { $types[$k] = 'theme'; continue; } $types[$k] = substr($v, $dlength + 1); } return $types; }
/** * Determine the module metadata for all moodle YUI modules. * * This works through all modules capable of serving YUI modules, and attempts to get * metadata for each of those modules. * * @return Array of module metadata */ private function get_moodle_metadata() { $moodlemodules = array(); // Core isn't a plugin type or subsystem - handle it seperately. if ($module = $this->get_moodle_path_metadata(core_component::get_component_directory('core'))) { $moodlemodules = array_merge($moodlemodules, $module); } // Handle other core subsystems. $subsystems = core_component::get_core_subsystems(); foreach ($subsystems as $subsystem => $path) { if (is_null($path)) { continue; } if ($module = $this->get_moodle_path_metadata($path)) { $moodlemodules = array_merge($moodlemodules, $module); } } // And finally the plugins. $plugintypes = core_component::get_plugin_types(); foreach ($plugintypes as $plugintype => $pathroot) { $pluginlist = core_component::get_plugin_list($plugintype); foreach ($pluginlist as $plugin => $path) { if ($module = $this->get_moodle_path_metadata($path)) { $moodlemodules = array_merge($moodlemodules, $module); } } } return $moodlemodules; }
/** * Returns an array of organised CSS files required for this output. * * @param bool $themedesigner * @return array nested array of file paths */ protected function get_css_files($themedesigner) { global $CFG; $cache = null; $cachekey = 'cssfiles'; if ($themedesigner) { require_once $CFG->dirroot . '/lib/csslib.php'; // We need some kind of caching here because otherwise the page navigation becomes // way too slow in theme designer mode. Feel free to create full cache definition later... $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'core', 'themedesigner', array('theme' => $this->name)); if ($files = $cache->get($cachekey)) { if ($files['created'] > time() - THEME_DESIGNER_CACHE_LIFETIME) { unset($files['created']); return $files; } } } $cssfiles = array('plugins' => array(), 'parents' => array(), 'theme' => array()); // Get all plugin sheets. $excludes = $this->resolve_excludes('plugins_exclude_sheets'); if ($excludes !== true) { foreach (core_component::get_plugin_types() as $type => $unused) { if ($type === 'theme' || (!empty($excludes[$type]) and $excludes[$type] === true)) { continue; } $plugins = core_component::get_plugin_list($type); foreach ($plugins as $plugin => $fulldir) { if (!empty($excludes[$type]) and is_array($excludes[$type]) and in_array($plugin, $excludes[$type])) { continue; } // Get the CSS from the plugin. $sheetfile = "{$fulldir}/styles.css"; if (is_readable($sheetfile)) { $cssfiles['plugins'][$type . '_' . $plugin] = $sheetfile; } // Create a list of candidate sheets from parents (direct parent last) and current theme. $candidates = array(); foreach (array_reverse($this->parent_configs) as $parent_config) { $candidates[] = $parent_config->name; } $candidates[] = $this->name; // Add the sheets found. foreach ($candidates as $candidate) { $sheetthemefile = "{$fulldir}/styles_{$candidate}.css"; if (is_readable($sheetthemefile)) { $cssfiles['plugins'][$type . '_' . $plugin . '_' . $candidate] = $sheetthemefile; } } } } } // Find out wanted parent sheets. $excludes = $this->resolve_excludes('parents_exclude_sheets'); if ($excludes !== true) { foreach (array_reverse($this->parent_configs) as $parent_config) { // Base first, the immediate parent last. $parent = $parent_config->name; if (empty($parent_config->sheets) || (!empty($excludes[$parent]) and $excludes[$parent] === true)) { continue; } foreach ($parent_config->sheets as $sheet) { if (!empty($excludes[$parent]) && is_array($excludes[$parent]) && in_array($sheet, $excludes[$parent])) { continue; } // We never refer to the parent LESS files. $sheetfile = "{$parent_config->dir}/style/{$sheet}.css"; if (is_readable($sheetfile)) { $cssfiles['parents'][$parent][$sheet] = $sheetfile; } } } } // Current theme sheets and less file. // We first add the LESS files because we want the CSS ones to be included after the // LESS code. However, if both the LESS file and the CSS file share the same name, // the CSS file is ignored. if (!empty($this->lessfile)) { $sheetfile = "{$this->dir}/less/{$this->lessfile}.less"; if (is_readable($sheetfile)) { $cssfiles['theme'][$this->lessfile] = $sheetfile; } } if (is_array($this->sheets)) { foreach ($this->sheets as $sheet) { $sheetfile = "{$this->dir}/style/{$sheet}.css"; if (is_readable($sheetfile) && !isset($cssfiles['theme'][$sheet])) { $cssfiles['theme'][$sheet] = $sheetfile; } } } if ($cache) { $files = $cssfiles; $files['created'] = time(); $cache->set($cachekey, $files); } return $cssfiles; }
/** * Get a list of folders to ignores. * * @param string $extraignorelist optional comma separated list of substring matching paths to ignore. * @return array of paths. */ function local_codesniffer_get_ignores($extraignorelist = '') { global $CFG; $files = array(); // XML files to be processed. $paths = array(); // Absolute paths to be excluded. $files['core'] = $CFG->libdir . DIRECTORY_SEPARATOR . '/thirdpartylibs.xml'; // This one always exists. // With MDL-42148, for 2.6 and upwards, the general 'thirdpartylibs.xml' file // has been split so any plugin with dependencies can have its own. In order to // keep master compatibility with older branches we are doing some // conditional coding here. if (file_exists($CFG->dirroot . '/' . $CFG->admin . '/' . 'thirdpartylibs.php')) { // New behavior, distributed XML files, let's look for them. $plugintypes = core_component::get_plugin_types(); foreach ($plugintypes as $type => $ignored) { $plugins = core_component::get_plugin_list_with_file($type, 'thirdpartylibs.xml', false); foreach ($plugins as $plugin => $path) { $files[$type . '_' . $plugin] = $path; } } } // Let's extract all the paths from the XML files. foreach ($files as $file) { $base = realpath(dirname($file)); $thirdparty = simplexml_load_file($file); foreach ($thirdparty->xpath('/libraries/library/location') as $location) { $location = substr($base, strlen($CFG->dirroot)) . '/' . $location; // This was happening since ages ago, leading to incorrect excluded // paths like: "/lib/theme/bootstrapbase/less/bootstrap", so we try // reducing it. Note this does not affect 2.6 and up, where all // locations are relative to their xml file so this problem cannot happen. if (!file_exists(dirname($CFG->dirroot . DIRECTORY_SEPARATOR . $location))) { // Only if it starts with '/lib'. if (strpos($location, DIRECTORY_SEPARATOR . 'lib') === 0) { $candidate = substr($location, strlen(DIRECTORY_SEPARATOR . 'lib')); // Only modify the original location if the candidate exists. if (file_exists(dirname($CFG->dirroot . DIRECTORY_SEPARATOR . $candidate))) { $location = $candidate; } } } // Accept only correct paths from XML files. if (file_exists(dirname($CFG->dirroot . DIRECTORY_SEPARATOR . $location))) { $paths[] = preg_quote(local_codechecker_clean_path($location)); } else { debugging("Processing {$file} for exclussions, incorrect {$location} path found. Please fix it"); } } } // Manually add our own pear stuff to be excluded. $paths[] = preg_quote(local_codechecker_clean_path('/local/codechecker' . DIRECTORY_SEPARATOR . 'pear')); // Changed in PHP_CodeSniffer 1.4.4 and upwards, so we apply the // same here: Paths go to keys and mark all them as 'absolute'. $finalpaths = array(); foreach ($paths as $pattern) { $finalpaths[$pattern] = 'absolute'; } // Let's add any substring matching path passed in $extraignorelist. if ($extraignorelist) { $extraignorearr = explode(',', $extraignorelist); foreach ($extraignorearr as $extraignore) { $extrapath = trim($extraignore); $finalpaths[$extrapath] = 'absolute'; } } return $finalpaths; }
/** * Returns the full path of the root of the given plugin type * * Null is returned if the plugin type is not known. False is returned if * the plugin type root is expected but not found. Otherwise, string is * returned. * * @param string $plugintype * @return string|bool|null */ public function get_plugintype_root($plugintype) { $plugintypepath = null; foreach (core_component::get_plugin_types() as $type => $fullpath) { if ($type === $plugintype) { $plugintypepath = $fullpath; break; } } if (is_null($plugintypepath)) { return null; } if (!is_dir($plugintypepath)) { return false; } return $plugintypepath; }
/** * Add subplugin structure for a given plugin to any element in the structure restore tree * * This method allows the injection of subplugins (of a specific plugin) parsing and proccessing * to any element in the restore structure. * * NOTE: Initially subplugins were only available for activities (mod), so only the * {@link restore_activity_structure_step} class had support for them, always * looking for /mod/modulenanme subplugins. This new method is a generalization of the * existing one for activities, supporting all subplugins injecting information everywhere. * * @param string $subplugintype type of subplugin as defined in plugin's db/subplugins.php. * @param restore_path_element $element element in the structure restore tree that * we are going to add subplugin information to. * @param string $plugintype type of the plugin. * @param string $pluginname name of the plugin. * @return void */ protected function add_subplugin_structure($subplugintype, $element, $plugintype = null, $pluginname = null) { global $CFG; // This global declaration is required, because where we do require_once($backupfile); // That file may in turn try to do require_once($CFG->dirroot ...). // That worked in the past, we should keep it working. // Verify if this is a BC call for an activity restore. See NOTE above for this special case. if ($plugintype === null and $pluginname === null) { $plugintype = 'mod'; $pluginname = $this->task->get_modulename(); // TODO: Once all the calls have been changed to add both not null plugintype and pluginname, add a debugging here. } // Check the requested plugintype is a valid one. if (!array_key_exists($plugintype, core_component::get_plugin_types())) { throw new restore_step_exception('incorrect_plugin_type', $plugintype); } // Check the requested pluginname, for the specified plugintype, is a valid one. if (!array_key_exists($pluginname, core_component::get_plugin_list($plugintype))) { throw new restore_step_exception('incorrect_plugin_name', array($plugintype, $pluginname)); } // Check the requested subplugintype is a valid one. $subpluginsfile = core_component::get_component_directory($plugintype . '_' . $pluginname) . '/db/subplugins.php'; if (!file_exists($subpluginsfile)) { throw new restore_step_exception('plugin_missing_subplugins_php_file', array($plugintype, $pluginname)); } include $subpluginsfile; if (!array_key_exists($subplugintype, $subplugins)) { throw new restore_step_exception('incorrect_subplugin_type', $subplugintype); } // Every subplugin optionally can have a common/parent subplugin // class for shared stuff. $parentclass = 'restore_' . $plugintype . '_' . $pluginname . '_' . $subplugintype . '_subplugin'; $parentfile = core_component::get_component_directory($plugintype . '_' . $pluginname) . '/backup/moodle2/' . $parentclass . '.class.php'; if (file_exists($parentfile)) { require_once $parentfile; } // Get all the restore path elements, looking across all the subplugin dirs. $subpluginsdirs = core_component::get_plugin_list($subplugintype); foreach ($subpluginsdirs as $name => $subpluginsdir) { $classname = 'restore_' . $subplugintype . '_' . $name . '_subplugin'; $restorefile = $subpluginsdir . '/backup/moodle2/' . $classname . '.class.php'; if (file_exists($restorefile)) { require_once $restorefile; $restoresubplugin = new $classname($subplugintype, $name, $this); // Add subplugin paths to the step. $this->prepare_pathelements($restoresubplugin->define_subplugin_structure($element)); } } }
/** * Builds dirroot/phpunit.xml and dataroot/phpunit/webrunner.xml files using defaults from /phpunit.xml.dist * @static * @return bool true means main config file created, false means only dataroot file created */ public static function build_config_file() { global $CFG; $template = ' <testsuite name="@component@ test suite"> <directory suffix="_test.php">@dir@</directory> </testsuite>'; $data = file_get_contents("{$CFG->dirroot}/phpunit.xml.dist"); $suites = ''; $plugintypes = core_component::get_plugin_types(); ksort($plugintypes); foreach ($plugintypes as $type => $unused) { $plugs = core_component::get_plugin_list($type); ksort($plugs); foreach ($plugs as $plug => $fullplug) { if (!file_exists("{$fullplug}/tests/")) { continue; } $dir = substr($fullplug, strlen($CFG->dirroot) + 1); $dir .= '/tests'; $component = $type . '_' . $plug; $suite = str_replace('@component@', $component, $template); $suite = str_replace('@dir@', $dir, $suite); $suites .= $suite; } } $data = preg_replace('|<!--@plugin_suites_start@-->.*<!--@plugin_suites_end@-->|s', $suites, $data, 1); $result = false; if (is_writable($CFG->dirroot)) { if ($result = file_put_contents("{$CFG->dirroot}/phpunit.xml", $data)) { testing_fix_file_permissions("{$CFG->dirroot}/phpunit.xml"); } } // relink - it seems that xml:base does not work in phpunit xml files, remove this nasty hack if you find a way to set xml base for relative refs $data = str_replace('lib/phpunit/', $CFG->dirroot . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'phpunit' . DIRECTORY_SEPARATOR, $data); $data = preg_replace('|<directory suffix="_test.php">([^<]+)</directory>|', '<directory suffix="_test.php">' . $CFG->dirroot . (DIRECTORY_SEPARATOR === '\\' ? '\\\\' : DIRECTORY_SEPARATOR) . '$1</directory>', $data); file_put_contents("{$CFG->dataroot}/phpunit/webrunner.xml", $data); testing_fix_file_permissions("{$CFG->dataroot}/phpunit/webrunner.xml"); return (bool) $result; }
/** * Very hacky function for rebuilding of log actions in target database. * @param moodle_database $target * @param progress_trace $feedback * @return void * @throws Exception on conversion error */ function tool_dbtransfer_rebuild_target_log_actions(moodle_database $target, progress_trace $feedback = null) { global $DB, $CFG; require_once "{$CFG->libdir}/upgradelib.php"; $feedback->output(get_string('convertinglogdisplay', 'tool_dbtransfer')); $olddb = $DB; $DB = $target; try { $DB->delete_records('log_display', array('component' => 'moodle')); log_update_descriptions('moodle'); $plugintypes = core_component::get_plugin_types(); foreach ($plugintypes as $type => $location) { $plugs = core_component::get_plugin_list($type); foreach ($plugs as $plug => $fullplug) { $component = $type . '_' . $plug; $DB->delete_records('log_display', array('component' => $component)); log_update_descriptions($component); } } } catch (Exception $e) { $DB = $olddb; throw $e; } $DB = $olddb; $feedback->output(get_string('done', 'core_dbtransfer', null), 1); }
/** * Builds dirroot/phpunit.xml and dataroot/phpunit/webrunner.xml files using defaults from /phpunit.xml.dist * @static * @return bool true means main config file created, false means only dataroot file created */ public static function build_config_file() { global $CFG; $template = ' <testsuite name="@component@_testsuite"> <directory suffix="_test.php">@dir@</directory> </testsuite>'; $data = file_get_contents("{$CFG->dirroot}/phpunit.xml.dist"); $suites = ''; $plugintypes = core_component::get_plugin_types(); ksort($plugintypes); foreach ($plugintypes as $type => $unused) { $plugs = core_component::get_plugin_list($type); ksort($plugs); foreach ($plugs as $plug => $fullplug) { if (!file_exists("{$fullplug}/tests/")) { continue; } $dir = substr($fullplug, strlen($CFG->dirroot) + 1); $dir .= '/tests'; $component = $type . '_' . $plug; $suite = str_replace('@component@', $component, $template); $suite = str_replace('@dir@', $dir, $suite); $suites .= $suite; } } // Start a sequence between 100000 and 199000 to ensure each call to init produces // different ids in the database. This reduces the risk that hard coded values will // end up being placed in phpunit or behat test code. $sequencestart = 100000 + mt_rand(0, 99) * 1000; $data = preg_replace('|<!--@plugin_suites_start@-->.*<!--@plugin_suites_end@-->|s', $suites, $data, 1); $data = str_replace('<const name="PHPUNIT_SEQUENCE_START" value=""/>', '<const name="PHPUNIT_SEQUENCE_START" value="' . $sequencestart . '"/>', $data); $result = false; if (is_writable($CFG->dirroot)) { if ($result = file_put_contents("{$CFG->dirroot}/phpunit.xml", $data)) { testing_fix_file_permissions("{$CFG->dirroot}/phpunit.xml"); } } // relink - it seems that xml:base does not work in phpunit xml files, remove this nasty hack if you find a way to set xml base for relative refs $data = str_replace('lib/phpunit/', $CFG->dirroot . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'phpunit' . DIRECTORY_SEPARATOR, $data); $data = preg_replace('|<directory suffix="_test.php">([^<]+)</directory>|', '<directory suffix="_test.php">' . $CFG->dirroot . (DIRECTORY_SEPARATOR === '\\' ? '\\\\' : DIRECTORY_SEPARATOR) . '$1</directory>', $data); file_put_contents("{$CFG->dataroot}/phpunit/webrunner.xml", $data); testing_fix_file_permissions("{$CFG->dataroot}/phpunit/webrunner.xml"); return (bool) $result; }
public function test_deprecated_get_component_directory() { $plugintypes = core_component::get_plugin_types(); foreach ($plugintypes as $plugintype => $fulldir) { $plugins = core_component::get_plugin_list($plugintype); foreach ($plugins as $pluginname => $plugindir) { $this->assertSame($plugindir, get_component_directory($plugintype . '_' . $pluginname)); } } $subsystems = core_component::get_core_subsystems(); foreach ($subsystems as $subsystem => $fulldir) { $this->assertSame($fulldir, get_component_directory('core_' . $subsystem)); } }
/** * Return the list of available search areas. * * @param bool $enabled Return only the enabled ones. * @return \core_search\area\base[] */ public static function get_search_areas_list($enabled = false) { // Two different arrays, we don't expect these arrays to be big. if (!$enabled && static::$allsearchareas !== null) { return static::$allsearchareas; } else { if ($enabled && static::$enabledsearchareas !== null) { return static::$enabledsearchareas; } } $searchareas = array(); $plugintypes = \core_component::get_plugin_types(); foreach ($plugintypes as $plugintype => $unused) { $plugins = \core_component::get_plugin_list($plugintype); foreach ($plugins as $pluginname => $pluginfullpath) { $componentname = $plugintype . '_' . $pluginname; $searchclasses = \core_component::get_component_classes_in_namespace($componentname, 'search'); foreach ($searchclasses as $classname => $classpath) { $areaname = substr(strrchr($classname, '\\'), 1); $areaid = static::generate_areaid($componentname, $areaname); $searchclass = new $classname(); if (!$enabled || $enabled && $searchclass->is_enabled()) { $searchareas[$areaid] = $searchclass; } } } } $subsystems = \core_component::get_core_subsystems(); foreach ($subsystems as $subsystemname => $subsystempath) { $componentname = 'core_' . $subsystemname; $searchclasses = \core_component::get_component_classes_in_namespace($componentname, 'search'); foreach ($searchclasses as $classname => $classpath) { $areaname = substr(strrchr($classname, '\\'), 1); $areaid = static::generate_areaid($componentname, $areaname); $searchclass = new $classname(); if (!$enabled || $enabled && $searchclass->is_enabled()) { $searchareas[$areaid] = $searchclass; } } } // Cache results. if ($enabled) { static::$enabledsearchareas = $searchareas; } else { static::$allsearchareas = $searchareas; } return $searchareas; }
// (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Script to refresh the services and external functions. * * @package mdk * @copyright 2015 Frédéric Massart - FMCorz.net * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ define('CLI_SCRIPT', true); require 'config.php'; require $CFG->libdir . '/upgradelib.php'; mtrace('Updating services of core'); external_update_descriptions('moodle'); $plugintypes = core_component::get_plugin_types(); foreach ($plugintypes as $plugintype => $dir) { $plugins = core_component::get_plugin_list($plugintype); foreach ($plugins as $plugin => $dir) { $component = $plugintype . '_' . $plugin; mtrace('Updating services of ' . $component); external_update_descriptions($component); } } external_update_services();
/** * This function will check for everything (DB, PHP and PHP extensions for now) * returning an array of environment_result objects. * * @global object * @param string $version xml version we are going to use to test this server * @param int $env_select one of ENV_SELECT_NEWER | ENV_SELECT_DATAROOT | ENV_SELECT_RELEASE decide xml to use. * @return environment_results[] array of results encapsulated in one environment_result object */ function environment_check($version, $env_select) { global $CFG; if ($env_select != ENV_SELECT_NEWER and $env_select != ENV_SELECT_DATAROOT and $env_select != ENV_SELECT_RELEASE) { throw new coding_exception('Incorrect value of $env_select parameter'); } /// Normalize the version requested $version = normalize_version($version); $results = array(); //To store all the results /// Only run the moodle versions checker on upgrade, not on install if (!empty($CFG->version)) { $results[] = environment_check_moodle($version, $env_select); } $results[] = environment_check_unicode($version, $env_select); $results[] = environment_check_database($version, $env_select); $results[] = environment_check_php($version, $env_select); if ($result = environment_check_pcre_unicode($version, $env_select)) { $results[] = $result; } $phpext_results = environment_check_php_extensions($version, $env_select); $results = array_merge($results, $phpext_results); $phpsetting_results = environment_check_php_settings($version, $env_select); $results = array_merge($results, $phpsetting_results); $custom_results = environment_custom_checks($version, $env_select); $results = array_merge($results, $custom_results); // Always use the plugin directory version of environment.xml, // add-on developers need to keep those up-to-date with future info. foreach (core_component::get_plugin_types() as $plugintype => $unused) { foreach (core_component::get_plugin_list_with_file($plugintype, 'environment.xml') as $pluginname => $unused) { $plugin = $plugintype . '_' . $pluginname; $result = environment_check_database($version, $plugin); if ($result->error_code != NO_VERSION_DATA_FOUND and $result->error_code != NO_DATABASE_SECTION_FOUND and $result->error_code != NO_DATABASE_VENDORS_FOUND) { $result->plugin = $plugin; $results[] = $result; } $result = environment_check_php($version, $plugin); if ($result->error_code != NO_VERSION_DATA_FOUND and $result->error_code != NO_PHP_SECTION_FOUND and $result->error_code != NO_PHP_VERSION_FOUND) { $result->plugin = $plugin; $results[] = $result; } $pluginresults = environment_check_php_extensions($version, $plugin); foreach ($pluginresults as $result) { if ($result->error_code != NO_VERSION_DATA_FOUND and $result->error_code != NO_PHP_EXTENSIONS_SECTION_FOUND) { $result->plugin = $plugin; $results[] = $result; } } $pluginresults = environment_check_php_settings($version, $plugin); foreach ($pluginresults as $result) { if ($result->error_code != NO_VERSION_DATA_FOUND) { $result->plugin = $plugin; $results[] = $result; } } $pluginresults = environment_custom_checks($version, $plugin); foreach ($pluginresults as $result) { if ($result->error_code != NO_VERSION_DATA_FOUND) { $result->plugin = $plugin; $results[] = $result; } } } } return $results; }
/** * Lists plugin-like directories within specified directory * * This function was originally used for standard Moodle plugins, please use * new core_component::get_plugin_list() now. * * This function is used for general directory listing and backwards compatility. * * @param string $directory relative directory from root * @param string $exclude dir name to exclude from the list (defaults to none) * @param string $basedir full path to the base dir where $plugin resides (defaults to $CFG->dirroot) * @return array Sorted array of directory names found under the requested parameters */ function get_list_of_plugins($directory = 'mod', $exclude = '', $basedir = '') { global $CFG; $plugins = array(); if (empty($basedir)) { $basedir = $CFG->dirroot . '/' . $directory; } else { $basedir = $basedir . '/' . $directory; } if ($CFG->debugdeveloper and empty($exclude)) { // Make sure devs do not use this to list normal plugins, // this is intended for general directories that are not plugins! $subtypes = core_component::get_plugin_types(); if (in_array($basedir, $subtypes)) { debugging('get_list_of_plugins() should not be used to list real plugins, use core_component::get_plugin_list() instead!', DEBUG_DEVELOPER); } unset($subtypes); } if (file_exists($basedir) && filetype($basedir) == 'dir') { if (!($dirhandle = opendir($basedir))) { debugging("Directory permission error for plugin ({$directory}). Directory exists but cannot be read.", DEBUG_DEVELOPER); return array(); } while (false !== ($dir = readdir($dirhandle))) { // Func: strpos is marginally but reliably faster than substr($dir, 0, 1). if (strpos($dir, '.') === 0 or $dir === 'CVS' or $dir === '_vti_cnf' or $dir === 'simpletest' or $dir === 'yui' or $dir === 'tests' or $dir === 'classes' or $dir === $exclude) { continue; } if (filetype($basedir . '/' . $dir) != 'dir') { continue; } $plugins[] = $dir; } closedir($dirhandle); } if ($plugins) { asort($plugins); } return $plugins; }
/** * Given a specific page type, parent context and currect context, return all the page type patterns * that might be used by this block. * * @param string $pagetype for example 'course-view-weeks' or 'mod-quiz-view'. * @param stdClass $parentcontext Block's parent context * @param stdClass $currentcontext Current context of block * @return array an array of all the page type patterns that might match this page type. */ function generate_page_type_patterns($pagetype, $parentcontext = null, $currentcontext = null) { global $CFG; // Required for includes bellow. $bits = explode('-', $pagetype); $core = core_component::get_core_subsystems(); $plugins = core_component::get_plugin_types(); //progressively strip pieces off the page type looking for a match $componentarray = null; for ($i = count($bits); $i > 0; $i--) { $possiblecomponentarray = array_slice($bits, 0, $i); $possiblecomponent = implode('', $possiblecomponentarray); // Check to see if the component is a core component if (array_key_exists($possiblecomponent, $core) && !empty($core[$possiblecomponent])) { $libfile = $core[$possiblecomponent] . '/lib.php'; if (file_exists($libfile)) { require_once $libfile; $function = $possiblecomponent . '_page_type_list'; if (function_exists($function)) { if ($patterns = $function($pagetype, $parentcontext, $currentcontext)) { break; } } } } //check the plugin directory and look for a callback if (array_key_exists($possiblecomponent, $plugins) && !empty($plugins[$possiblecomponent])) { //We've found a plugin type. Look for a plugin name by getting the next section of page type if (count($bits) > $i) { $pluginname = $bits[$i]; $directory = core_component::get_plugin_directory($possiblecomponent, $pluginname); if (!empty($directory)) { $libfile = $directory . '/lib.php'; if (file_exists($libfile)) { require_once $libfile; $function = $possiblecomponent . '_' . $pluginname . '_page_type_list'; if (!function_exists($function)) { $function = $pluginname . '_page_type_list'; } if (function_exists($function)) { if ($patterns = $function($pagetype, $parentcontext, $currentcontext)) { break; } } } } } //we'll only get to here if we still don't have any patterns //the plugin type may have a callback $directory = $plugins[$possiblecomponent]; $libfile = $directory . '/lib.php'; if (file_exists($libfile)) { require_once $libfile; $function = $possiblecomponent . '_page_type_list'; if (function_exists($function)) { if ($patterns = $function($pagetype, $parentcontext, $currentcontext)) { break; } } } } } if (empty($patterns)) { $patterns = default_page_type_list($pagetype, $parentcontext, $currentcontext); } // Ensure that the * pattern is always available if editing block 'at distance', so // we always can 'bring back' it to the original context. MDL-30340 if ((!isset($currentcontext) or !isset($parentcontext) or $currentcontext->id != $parentcontext->id) && !isset($patterns['*'])) { // TODO: We could change the string here, showing its 'bring back' meaning $patterns['*'] = get_string('page-x', 'pagetype'); } return $patterns; }
/** * This function returns an array of all events for the plugins of the system. * * @param bool $detail True will return details, but no abstract classes, False will return all events, but no details. * @return array A list of events from all plug-ins. */ public static function get_non_core_event_list($detail = true) { global $CFG; // Disable developer debugging as deprecated events will fire warnings. // Setup backup variables to restore the following settings back to what they were when we are finished. $debuglevel = $CFG->debug; $debugdisplay = $CFG->debugdisplay; $debugdeveloper = $CFG->debugdeveloper; $CFG->debug = 0; $CFG->debugdisplay = false; $CFG->debugdeveloper = false; $noncorepluginlist = array(); $plugintypes = \core_component::get_plugin_types(); foreach ($plugintypes as $plugintype => $notused) { $pluginlist = \core_component::get_plugin_list($plugintype); foreach ($pluginlist as $plugin => $directory) { $plugindirectory = $directory . '/classes/event'; foreach (self::get_file_list($plugindirectory) as $eventname => $notused) { $plugineventname = '\\' . $plugintype . '_' . $plugin . '\\event\\' . $eventname; // Check that this is actually an event. if (method_exists($plugineventname, 'get_static_info')) { if ($detail) { $ref = new \ReflectionClass($plugineventname); if (!$ref->isAbstract() && $plugintype . '_' . $plugin !== 'logstore_legacy') { $noncorepluginlist = self::format_data($noncorepluginlist, $plugineventname); } } else { $noncorepluginlist[$plugineventname] = $eventname; } } } } } // Now enable developer debugging as event information has been retrieved. $CFG->debug = $debuglevel; $CFG->debugdisplay = $debugdisplay; $CFG->debugdeveloper = $debugdeveloper; return $noncorepluginlist; }
/** * This function will generate the PHP code needed to * implement the upgrade_xxxx_savepoint() php calls in * upgrade code generated from the editor. It's used by * the view_structure_php and view_table_php actions * * @param xmldb_structure structure object containing all the info * @return string PHP code to be used to mark a reached savepoint */ function upgrade_savepoint_php($structure) { global $CFG; // NOTE: $CFG->admin !== 'admin' is not supported in XMLDB editor, sorry. $path = $structure->getPath(); $plugintype = 'error'; if ($path === 'lib/db') { $plugintype = 'lib'; $pluginname = null; } else { $path = dirname($path); $pluginname = basename($path); $path = dirname($path); $plugintypes = core_component::get_plugin_types(); foreach ($plugintypes as $type => $fulldir) { if ($CFG->dirroot . '/' . $path === $fulldir) { $plugintype = $type; break; } } } $result = ''; switch ($plugintype) { case 'lib': // has own savepoint function $result = XMLDB_LINEFEED . ' // Main savepoint reached.' . XMLDB_LINEFEED . ' upgrade_main_savepoint(true, XXXXXXXXXX);' . XMLDB_LINEFEED; break; case 'mod': // has own savepoint function $result = XMLDB_LINEFEED . ' // ' . ucfirst($pluginname) . ' savepoint reached.' . XMLDB_LINEFEED . ' upgrade_mod_savepoint(true, XXXXXXXXXX, ' . "'{$pluginname}'" . ');' . XMLDB_LINEFEED; break; case 'block': // has own savepoint function $result = XMLDB_LINEFEED . ' // ' . ucfirst($pluginname) . ' savepoint reached.' . XMLDB_LINEFEED . ' upgrade_block_savepoint(true, XXXXXXXXXX, ' . "'{$pluginname}'" . ');' . XMLDB_LINEFEED; break; default: // rest of plugins $result = XMLDB_LINEFEED . ' // ' . ucfirst($pluginname) . ' savepoint reached.' . XMLDB_LINEFEED . ' upgrade_plugin_savepoint(true, XXXXXXXXXX, ' . "'{$plugintype}'" . ', ' . "'{$pluginname}'" . ');' . XMLDB_LINEFEED; } return $result; }
/** * Returns list of all directories where we expect install.xml files * @return array Array of paths */ function get_db_directories() { global $CFG; $dbdirs = array(); /// First, the main one (lib/db) $dbdirs[] = $CFG->libdir . '/db'; /// Then, all the ones defined by core_component::get_plugin_types() $plugintypes = core_component::get_plugin_types(); foreach ($plugintypes as $plugintype => $pluginbasedir) { if ($plugins = core_component::get_plugin_list($plugintype)) { foreach ($plugins as $plugin => $plugindir) { $dbdirs[] = $plugindir . '/db'; } } } return $dbdirs; }
/** * Returns list of plugins that define their subplugins and the information * about them from the db/subplugins.php file. * * @return array with keys like 'mod_quiz', and values the data from the * corresponding db/subplugins.php file. */ public function get_subplugins() { if (is_array($this->subpluginsinfo)) { return $this->subpluginsinfo; } $plugintypes = core_component::get_plugin_types(); $this->subpluginsinfo = array(); foreach (core_component::get_plugin_types_with_subplugins() as $type => $ignored) { foreach (core_component::get_plugin_list($type) as $plugin => $componentdir) { $component = $type . '_' . $plugin; $subplugins = core_component::get_subplugins($component); if (!$subplugins) { continue; } $this->subpluginsinfo[$component] = array(); foreach ($subplugins as $subplugintype => $ignored) { $subplugin = new stdClass(); $subplugin->type = $subplugintype; $subplugin->typerootdir = $plugintypes[$subplugintype]; $this->subpluginsinfo[$component][$subplugintype] = $subplugin; } } } return $this->subpluginsinfo; }
/** * Returns hash of all versions including core and all plugins. * * This is relatively slow and not fully cached, use with care! * * @return string sha1 hash */ public static function get_all_versions_hash() { global $CFG; self::init(); $versions = array(); // Main version first. $versions['core'] = self::fetch_core_version(); // The problem here is tha the component cache might be stable, // we want this to work also on frontpage without resetting the component cache. $usecache = false; if (CACHE_DISABLE_ALL or defined('IGNORE_COMPONENT_CACHE') and IGNORE_COMPONENT_CACHE) { $usecache = true; } // Now all plugins. $plugintypes = core_component::get_plugin_types(); foreach ($plugintypes as $type => $typedir) { if ($usecache) { $plugs = core_component::get_plugin_list($type); } else { $plugs = self::fetch_plugins($type, $typedir); } foreach ($plugs as $plug => $fullplug) { $plugin = new stdClass(); $plugin->version = null; $module = $plugin; @(include $fullplug . '/version.php'); $versions[$type . '_' . $plug] = $plugin->version; } } return sha1(serialize($versions)); }
/** * Upgrade/install other parts of moodle * @param bool $verbose * @return void, may throw exception */ function upgrade_noncore($verbose) { global $CFG; raise_memory_limit(MEMORY_EXTRA); // upgrade all plugins types try { // Reset caches before any output. cache_helper::purge_all(true); purge_all_caches(); $plugintypes = core_component::get_plugin_types(); foreach ($plugintypes as $type => $location) { upgrade_plugins($type, 'print_upgrade_part_start', 'print_upgrade_part_end', $verbose); } // Update cache definitions. Involves scanning each plugin for any changes. cache_helper::update_definitions(); // Mark the site as upgraded. set_config('allversionshash', core_component::get_all_versions_hash()); // Purge caches again, just to be sure we arn't holding onto old stuff now. cache_helper::purge_all(true); purge_all_caches(); } catch (Exception $ex) { upgrade_handle_exception($ex); } }