Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 400 and 402] [Versions 400 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Class containing helper methods for processing data requests.
  19   *
  20   * @package    tool_dataprivacy
  21   * @copyright  2018 Adrian Greeve
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  namespace tool_dataprivacy;
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  /**
  29   * Class containing helper methods for processing data requests.
  30   *
  31   * @copyright  2018 Adrian Greeve
  32   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  33   */
  34  class metadata_registry {
  35  
  36      /**
  37       * Returns plugin types / plugins and the user data that it stores in a format that can be sent to a template.
  38       *
  39       * @return array An array with all of the plugin types / plugins and the user data they store.
  40       */
  41      public function get_registry_metadata() {
  42          $manager = new \core_privacy\manager();
  43          $manager->set_observer(new \tool_dataprivacy\manager_observer());
  44  
  45          $pluginman = \core_plugin_manager::instance();
  46          $contributedplugins = $this->get_contrib_list();
  47          $metadata = $manager->get_metadata_for_components();
  48          $fullyrichtree = $this->get_full_component_list();
  49          foreach ($fullyrichtree as $branch => $leaves) {
  50              $plugintype = $leaves['plugin_type'];
  51              $plugins = array_map(function($component) use ($manager, $metadata, $contributedplugins, $plugintype, $pluginman) {
  52                  // Use the plugin name for the plugins, ignore for core subsystems.
  53                  $internaldata = ($plugintype == 'core') ? ['component' => $component] :
  54                          ['component' => $pluginman->plugin_name($component)];
  55                  $internaldata['raw_component'] = $component;
  56                  if ($manager->component_is_compliant($component)) {
  57                      $internaldata['compliant'] = true;
  58                      if (isset($metadata[$component])) {
  59                          $collection = $metadata[$component]->get_collection();
  60                          $internaldata = $this->format_metadata($collection, $component, $internaldata);
  61                      } else if ($manager->is_empty_subsystem($component)) {
  62                          // This is an unused subsystem.
  63                          // Use the generic string.
  64                          $internaldata['nullprovider'] = get_string('privacy:subsystem:empty', 'core_privacy');
  65                      } else {
  66                          // Call get_reason for null provider.
  67                          $internaldata['nullprovider'] = get_string($manager->get_null_provider_reason($component), $component);
  68                      }
  69                  } else {
  70                      $internaldata['compliant'] = false;
  71                  }
  72                  // Check to see if we are an external plugin.
  73                  // Plugin names can contain _ characters, limit to 2 to just remove initial plugintype.
  74                  $componentshortname = explode('_', $component, 2);
  75                  $shortname = array_pop($componentshortname);
  76                  if (isset($contributedplugins[$plugintype][$shortname])) {
  77                      $internaldata['external'] = true;
  78                  }
  79  
  80                  // Additional interface checks.
  81                  if (!$manager->is_empty_subsystem($component)) {
  82                      $classname = $manager->get_provider_classname_for_component($component);
  83                      if (class_exists($classname)) {
  84                          $componentclass = new $classname();
  85                          // Check if the interface is deprecated.
  86                          if ($componentclass instanceof \core_privacy\local\deprecated) {
  87                              $internaldata['deprecated'] = true;
  88                          }
  89  
  90                          // Check that the core_userlist_provider is implemented for all user data providers.
  91                          if ($componentclass instanceof \core_privacy\local\request\core_user_data_provider
  92                                  && !$componentclass instanceof \core_privacy\local\request\core_userlist_provider) {
  93                              $internaldata['userlistnoncompliance'] = true;
  94                          }
  95  
  96                          // Check that any type of userlist_provider is implemented for all shared data providers.
  97                          if ($componentclass instanceof \core_privacy\local\request\shared_data_provider
  98                                  && !$componentclass instanceof \core_privacy\local\request\userlist_provider) {
  99                              $internaldata['userlistnoncompliance'] = true;
 100                          }
 101                      }
 102                  }
 103  
 104                  return $internaldata;
 105              }, $leaves['plugins']);
 106              $fullyrichtree[$branch]['plugin_type_raw'] = $plugintype;
 107              // We're done using the plugin type. Convert it to a readable string.
 108              $fullyrichtree[$branch]['plugin_type'] = $pluginman->plugintype_name($plugintype);
 109              $fullyrichtree[$branch]['plugins'] = $plugins;
 110          }
 111          return $fullyrichtree;
 112      }
 113  
 114      /**
 115       * Formats the metadata for use with a template.
 116       *
 117       * @param  array $collection The collection associated with the component that we want to expand and format.
 118       * @param  string $component The component that we are dealing in
 119       * @param  array $internaldata The array to add the formatted metadata to.
 120       * @return array The internal data array with the formatted metadata.
 121       */
 122      protected function format_metadata($collection, $component, $internaldata) {
 123          foreach ($collection as $collectioninfo) {
 124              $privacyfields = $collectioninfo->get_privacy_fields();
 125              $fields = '';
 126              if (!empty($privacyfields)) {
 127                  $fields = array_map(function($key, $field) use ($component) {
 128                      return [
 129                          'field_name' => $key,
 130                          'field_summary' => get_string($field, $component)
 131                      ];
 132                  }, array_keys($privacyfields), $privacyfields);
 133              }
 134              // Can the metadata types be located somewhere else besides core?
 135              $items = explode('\\', get_class($collectioninfo));
 136              $type = array_pop($items);
 137              $typedata = [
 138                  'name' => $collectioninfo->get_name(),
 139                  'type' => $type,
 140                  'fields' => $fields,
 141                  'summary' => get_string($collectioninfo->get_summary(), $component)
 142              ];
 143              if (strpos($type, 'subsystem_link') === 0 || strpos($type, 'plugintype_link') === 0) {
 144                  $typedata['link'] = true;
 145              }
 146              $internaldata['metadata'][] = $typedata;
 147          }
 148          return $internaldata;
 149      }
 150  
 151      /**
 152       * Return the full list of components.
 153       *
 154       * @return array An array of plugin types which contain plugin data.
 155       */
 156      protected function get_full_component_list() {
 157          global $CFG;
 158  
 159          $list = \core_component::get_component_list();
 160          $list['core']['core'] = "{$CFG->dirroot}/lib";
 161          $formattedlist = [];
 162          foreach ($list as $plugintype => $plugin) {
 163              $formattedlist[] = ['plugin_type' => $plugintype, 'plugins' => array_keys($plugin)];
 164          }
 165  
 166          return $formattedlist;
 167      }
 168  
 169      /**
 170       * Returns a list of contributed plugins installed on the system.
 171       *
 172       * @return array A list of contributed plugins installed.
 173       */
 174      protected function get_contrib_list() {
 175          return array_map(function($plugins) {
 176              return array_filter($plugins, function($plugindata) {
 177                  return !$plugindata->is_standard();
 178              });
 179          }, \core_plugin_manager::instance()->get_plugins());
 180      }
 181  }