1. 8.3.x core/modules/system/system.module
  2. 8.0.x core/modules/system/system.module
  3. 8.1.x core/modules/system/system.module
  4. 8.2.x core/modules/system/system.module
  5. 8.4.x core/modules/system/system.module
  6. 4.6.x modules/system.module
  7. 4.7.x modules/system.module
  8. 5.x modules/system/system.module
  9. 6.x modules/system/system.module
  10. 7.x modules/system/system.module

Configuration system that lets administrators modify the workings of the site.

File

core/modules/system/system.module
View source
  1. <?php
  2. /**
  3. * @file
  4. * Configuration system that lets administrators modify the workings of the site.
  5. */
  6. use Drupal\Component\Render\PlainTextOutput;
  7. use Drupal\Component\Utility\UrlHelper;
  8. use Drupal\Core\Asset\AttachedAssetsInterface;
  9. use Drupal\Core\Cache\Cache;
  10. use Drupal\Core\Queue\QueueGarbageCollectionInterface;
  11. use Drupal\Core\Database\Query\AlterableInterface;
  12. use Drupal\Core\Extension\Extension;
  13. use Drupal\Core\Extension\ExtensionDiscovery;
  14. use Drupal\Core\Form\FormStateInterface;
  15. use Drupal\Core\KeyValueStore\KeyValueDatabaseExpirableFactory;
  16. use Drupal\Core\PageCache\RequestPolicyInterface;
  17. use Drupal\Core\PhpStorage\PhpStorageFactory;
  18. use Drupal\Core\Routing\RouteMatchInterface;
  19. use Drupal\Core\Routing\StackedRouteMatchInterface;
  20. use Drupal\Core\Language\LanguageInterface;
  21. use Drupal\Core\Menu\MenuTreeParameters;
  22. use Drupal\Core\Extension\ModuleHandler;
  23. use Drupal\Core\Url;
  24. use Drupal\Core\Block\BlockPluginInterface;
  25. use Drupal\user\UserInterface;
  26. use Symfony\Component\HttpFoundation\RedirectResponse;
  27. use GuzzleHttp\Exception\RequestException;
  28. /**
  29. * New users will be set to the default time zone at registration.
  30. */
  31. const DRUPAL_USER_TIMEZONE_DEFAULT = 0;
  32. /**
  33. * New users will get an empty time zone at registration.
  34. */
  35. const DRUPAL_USER_TIMEZONE_EMPTY = 1;
  36. /**
  37. * New users will select their own timezone at registration.
  38. */
  39. const DRUPAL_USER_TIMEZONE_SELECT = 2;
  40. /**
  41. * Disabled option on forms and settings
  42. */
  43. const DRUPAL_DISABLED = 0;
  44. /**
  45. * Optional option on forms and settings
  46. */
  47. const DRUPAL_OPTIONAL = 1;
  48. /**
  49. * Required option on forms and settings
  50. */
  51. const DRUPAL_REQUIRED = 2;
  52. /**
  53. * Return only visible regions.
  54. *
  55. * @see system_region_list()
  56. */
  57. const REGIONS_VISIBLE = 'visible';
  58. /**
  59. * Return all regions.
  60. *
  61. * @see system_region_list()
  62. */
  63. const REGIONS_ALL = 'all';
  64. /**
  65. * Implements hook_help().
  66. */
  67. function system_help($route_name, RouteMatchInterface $route_match) {
  68. switch ($route_name) {
  69. case 'help.page.system':
  70. $output = '';
  71. $output .= '<h3>' . t('About') . '</h3>';
  72. $output .= '<p>' . t('The System module is integral to the site: it provides user interfaces for many core systems and settings, as well as the basic administrative menu structure. For more information, see the <a href=":system">online documentation for the System module</a>.', array(':system' => 'https://www.drupal.org/documentation/modules/system')) . '</p>';
  73. $output .= '<h3>' . t('Uses') . '</h3>';
  74. $output .= '<dl>';
  75. $output .= '<dt>' . t('Managing modules') . '</dt>';
  76. $output .= '<dd>' . t('Users with appropriate permission can install and uninstall modules from the <a href=":modules">Extend page</a>. Depending on which distribution or installation profile you choose when you install your site, several modules are installed and others are provided but not installed. Each module provides a discrete set of features; modules may be installed or uninstalled depending on the needs of the site. Many additional modules contributed by members of the Drupal community are available for download from the <a href=":drupal-modules">Drupal.org module page</a>. Note that uninstalling a module is a destructive action: when you uninstall a module, you will permanently lose all data connected to the module.', array(':modules' => \Drupal::url('system.modules_list'), ':drupal-modules' => 'https://www.drupal.org/project/modules')) . '</dd>';
  77. $output .= '<dt>' . t('Managing themes') . '</dt>';
  78. $output .= '<dd>' . t('Users with appropriate permission can install and uninstall themes on the <a href=":themes">Appearance page</a>. Themes determine the design and presentation of your site. Depending on which distribution or installation profile you choose when you install your site, a default theme is installed, and possibly a different theme for administration pages. Other themes are provided but not installed, and additional contributed themes are available at the <a href=":drupal-themes">Drupal.org theme page</a>.', array(':themes' => \Drupal::url('system.themes_page'), ':drupal-themes' => 'https://www.drupal.org/project/themes')) . '</dd>';
  79. $output .= '<dt>' . t('Disabling drag-and-drop functionality') . '</dt>';
  80. $output .= '<dd>' . t('The default drag-and-drop user interface for ordering tables in the administrative interface presents a challenge for some users, including users of screen readers and other assistive technology. The drag-and-drop interface can be disabled in a table by clicking a link labeled "Show row weights" above the table. The replacement interface allows users to order the table by choosing numerical weights instead of dragging table rows.') . '</dd>';
  81. $output .= '<dt>' . t('Configuring basic site settings') . '</dt>';
  82. $output .= '<dd>' . t('The System module provides pages for managing basic site configuration, including <a href=":date-time-settings">Date and time formats</a> and <a href=":site-info">Basic site settings</a> (site name, email address to send mail from, home page, and error pages). Additional configuration pages are listed on the main <a href=":config">Configuration page</a>.', array(':date-time-settings' => \Drupal::url('entity.date_format.collection'), ':site-info' => \Drupal::url('system.site_information_settings'), ':config' => \Drupal::url('system.admin_config'))) . '</dd>';
  83. $output .= '<dt>' . t('Checking site status') . '</dt>';
  84. $output .= '<dd>' . t('The <a href=":status">Status report</a> provides an overview of the configuration, status, and health of your site. Review this report to make sure there are not any problems to address, and to find information about the software your site and web server are using.', array(':status' => \Drupal::url('system.status'))) . '</dd>';
  85. $output .= '<dt>' . t('Using maintenance mode') . '</dt>';
  86. $output .= '<dd>' . t('When you are performing site maintenance, you can prevent non-administrative users (including anonymous visitors) from viewing your site by putting it in <a href=":maintenance-mode">Maintenance mode</a>. This will prevent unauthorized users from making changes to the site while you are performing maintenance, or from seeing a broken site while updates are in progress.', array(':maintenance-mode' => \Drupal::url('system.site_maintenance_mode'))) . '</dd>';
  87. $output .= '<dt>' . t('Configuring for performance') . '</dt>';
  88. $output .= '<dd>' . t('On the <a href=":performance-page">Performance page</a>, the site can be configured to aggregate CSS and JavaScript files, making the total request size smaller. Note that, for small- to medium-sized websites, the <a href=":page-cache">Internal Page Cache module</a> should be installed so that pages are efficiently cached and reused for anonymous users. Finally, for websites of all sizes, the <a href=":dynamic-page-cache">Dynamic Page Cache module</a> should also be installed so that the non-personalized parts of pages are efficiently cached (for all users).', array(':performance-page' => \Drupal::url('system.performance_settings'), ':page-cache' => (\Drupal::moduleHandler()->moduleExists('page_cache')) ? \Drupal::url('help.page', array('name' => 'page_cache')) : '#', ':dynamic-page-cache' => (\Drupal::moduleHandler()->moduleExists('dynamic_page_cache')) ? \Drupal::url('help.page', array('name' => 'dynamic_page_cache')) : '#')) . '</dd>';
  89. $output .= '<dt>' . t('Configuring cron') . '</dt>';
  90. $output .= '<dd>' . t('In order for the site and its modules to continue to operate well, a set of routine administrative operations must run on a regular basis; these operations are known as <em>cron</em> tasks. On the <a href=":cron">Cron page</a>, you can configure cron to run periodically as part of server responses by installing the <em>Automated Cron</em> module, or you can turn this off and trigger cron from an outside process on your web server. You can verify the status of cron tasks by visiting the <a href=":status">Status report page</a>. For more information, see the <a href=":handbook">online documentation for configuring cron jobs</a>.', array(':status' => \Drupal::url('system.status'), ':handbook' => 'https://www.drupal.org/cron', ':cron' => \Drupal::url('system.cron_settings'))) . '</dd>';
  91. $output .= '<dt>' . t('Configuring the file system') . '</dt>';
  92. $output .= '<dd>' . t('Your site has several file directories, which are used to store and process uploaded and generated files. The <em>public</em> file directory, which is configured in your settings.php file, is the default place for storing uploaded files. Links to files in this directory contain the direct file URL, so when the files are requested, the web server will send them directly without invoking your site code. This means that the files can be downloaded by anyone with the file URL, so requests are not access-controlled but they are efficient. The <em>private</em> file directory, also configured in your settings.php file and ideally located outside the site web root, is access controlled. Links to files in this directory are not direct, so requests to these files are mediated by your site code. This means that your site can check file access permission for each file before deciding to fulfill the request, so the requests are more secure, but less efficient. You should only use the private storage for files that need access control, not for files like your site logo and background images used on every page. The <em>temporary</em> file directory is used internally by your site code for various operations, and is configured on the <a href=":file-system">File system settings</a> page. You can also see the configured public and private file directories on this page, and choose whether public or private should be the default for uploaded files.', array(':file-system' => \Drupal::url('system.file_system_settings'))) . '</dd>';
  93. $output .= '<dt>' . t('Configuring the image toolkit') . '</dt>';
  94. $output .= '<dd>' . t('On the <a href=":toolkit">Image toolkit page</a>, you can select and configure the PHP toolkit used to manipulate images. Depending on which distribution or installation profile you choose when you install your site, the GD2 toolkit and possibly others are included; other toolkits may be provided by contributed modules.', array(':toolkit' => \Drupal::url('system.image_toolkit_settings'))) . '</dd>';
  95. $output .= '</dl>';
  96. return $output;
  97. case 'system.admin_index':
  98. return '<p>' . t('This page shows you all available administration tasks for each module.') . '</p>';
  99. case 'system.themes_page':
  100. $output = '<p>' . t('Set and configure the default theme for your website. Alternative <a href=":themes">themes</a> are available.', array(':themes' => 'https://www.drupal.org/project/themes')) . '</p>';
  101. if (\Drupal::moduleHandler()->moduleExists('block')) {
  102. $output .= '<p>' . t('You can place blocks for each theme on the <a href=":blocks">block layout</a> page.', array(':blocks' => \Drupal::url('block.admin_display'))) . '</p>';
  103. }
  104. return $output;
  105. case 'system.theme_settings_theme':
  106. $theme_list = \Drupal::service('theme_handler')->listInfo();
  107. $theme = $theme_list[$route_match->getParameter('theme')];
  108. return '<p>' . t('These options control the display settings for the %name theme. When your site is displayed using this theme, these settings will be used.', array('%name' => $theme->info['name'])) . '</p>';
  109. case 'system.theme_settings':
  110. return '<p>' . t('Control default display settings for your site, across all themes. Use theme-specific settings to override these defaults.') . '</p>';
  111. case 'system.modules_list':
  112. $output = '<p>' . t('Download additional <a href=":modules">contributed modules</a> to extend your site\'s functionality.', array(':modules' => 'https://www.drupal.org/project/modules')) . '</p>';
  113. if (!\Drupal::moduleHandler()->moduleExists('update')) {
  114. $output .= '<p>' . t('Regularly review available updates to maintain a secure and current site. Always run the <a href=":update-php">update script</a> each time a module is updated. Enable the <a href=":update-manager">Update Manager module</a> to update and install modules and themes.', array(':update-php' => \Drupal::url('system.db_update'), ':update-manager' => \Drupal::url('system.modules_list', [], ['fragment' => 'module-update']))) . '</p>';
  115. }
  116. return $output;
  117. case 'system.modules_uninstall':
  118. return '<p>' . t('The uninstall process removes all data related to a module.') . '</p>';
  119. case 'entity.block.edit_form':
  120. if (($block = $route_match->getParameter('block')) && $block->getPluginId() == 'system_powered_by_block') {
  121. return '<p>' . t('The <em>Powered by Drupal</em> block is an optional link to the home page of the Drupal project. While there is absolutely no requirement that sites feature this link, it may be used to show support for Drupal.') . '</p>';
  122. }
  123. break;
  124. case 'block.admin_add':
  125. if ($route_match->getParameter('plugin_id') == 'system_powered_by_block') {
  126. return '<p>' . t('The <em>Powered by Drupal</em> block is an optional link to the home page of the Drupal project. While there is absolutely no requirement that sites feature this link, it may be used to show support for Drupal.') . '</p>';
  127. }
  128. break;
  129. case 'system.site_maintenance_mode':
  130. if (\Drupal::currentUser()->id() == 1) {
  131. return '<p>' . t('Use maintenance mode when making major updates, particularly if the updates could disrupt visitors or the update process. Examples include upgrading, importing or exporting content, modifying a theme, modifying content types, and making backups.') . '</p>';
  132. }
  133. break;
  134. case 'system.status':
  135. return '<p>' . t("Here you can find a short overview of your site's parameters as well as any problems detected with your installation. It may be useful to copy and paste this information into support requests filed on Drupal.org's support forums and project issue queues. Before filing a support request, ensure that your web server meets the <a href=\":system-requirements\">system requirements.</a>", array(':system-requirements' => 'https://www.drupal.org/requirements')) . '</p>';
  136. }
  137. }
  138. /**
  139. * Implements hook_theme().
  140. */
  141. function system_theme() {
  142. return array_merge(drupal_common_theme(), array(
  143. // Normally theme suggestion templates are only picked up when they are in
  144. // themes. We explicitly define theme suggestions here so that the block
  145. // templates in core/modules/system/templates are picked up.
  146. 'block__system_branding_block' => array(
  147. 'render element' => 'elements',
  148. 'base hook' => 'block',
  149. ),
  150. 'block__system_messages_block' => array(
  151. 'base hook' => 'block',
  152. ),
  153. 'block__system_menu_block' => array(
  154. 'render element' => 'elements',
  155. 'base hook' => 'block',
  156. ),
  157. 'system_themes_page' => array(
  158. 'variables' => array(
  159. 'theme_groups' => array(),
  160. 'theme_group_titles' => array(),
  161. ),
  162. 'file' => 'system.admin.inc',
  163. ),
  164. 'system_config_form' => array(
  165. 'render element' => 'form',
  166. ),
  167. 'confirm_form' => array(
  168. 'render element' => 'form',
  169. ),
  170. 'system_modules_details' => array(
  171. 'render element' => 'form',
  172. 'file' => 'system.admin.inc',
  173. ),
  174. 'system_modules_uninstall' => array(
  175. 'render element' => 'form',
  176. 'file' => 'system.admin.inc',
  177. ),
  178. 'status_report' => array(
  179. 'variables' => array('requirements' => NULL),
  180. 'file' => 'system.admin.inc',
  181. ),
  182. 'admin_page' => array(
  183. 'variables' => array('blocks' => NULL),
  184. 'file' => 'system.admin.inc',
  185. ),
  186. 'admin_block' => array(
  187. 'variables' => array('block' => NULL),
  188. 'file' => 'system.admin.inc',
  189. ),
  190. 'admin_block_content' => array(
  191. 'variables' => array('content' => NULL),
  192. 'file' => 'system.admin.inc',
  193. ),
  194. 'system_admin_index' => array(
  195. 'variables' => array('menu_items' => NULL),
  196. 'file' => 'system.admin.inc',
  197. ),
  198. 'entity_add_list' => array(
  199. 'variables' => array(
  200. 'bundles' => array(),
  201. 'add_bundle_message' => NULL,
  202. ),
  203. 'template' => 'entity-add-list',
  204. ),
  205. ));
  206. }
  207. /**
  208. * Implements hook_hook_info().
  209. */
  210. function system_hook_info() {
  211. $hooks['token_info'] = array(
  212. 'group' => 'tokens',
  213. );
  214. $hooks['token_info_alter'] = array(
  215. 'group' => 'tokens',
  216. );
  217. $hooks['tokens'] = array(
  218. 'group' => 'tokens',
  219. );
  220. $hooks['tokens_alter'] = array(
  221. 'group' => 'tokens',
  222. );
  223. return $hooks;
  224. }
  225. /**
  226. * Implements hook_theme_suggestions_HOOK().
  227. */
  228. function system_theme_suggestions_html(array $variables) {
  229. if (\Drupal::service('path.matcher')->isFrontPage()) {
  230. $path_args = [''];
  231. }
  232. else {
  233. $path_args = explode('/', ltrim(\Drupal::service('path.current')->getPath(), '/'));
  234. }
  235. return theme_get_suggestions($path_args, 'html');
  236. }
  237. /**
  238. * Implements hook_theme_suggestions_HOOK().
  239. */
  240. function system_theme_suggestions_page(array $variables) {
  241. if (\Drupal::service('path.matcher')->isFrontPage()) {
  242. $path_args = [''];
  243. }
  244. else {
  245. $path_args = explode('/', Url::fromRoute('<current>')->getInternalPath());
  246. }
  247. return theme_get_suggestions($path_args, 'page');
  248. }
  249. /**
  250. * Implements hook_theme_suggestions_HOOK().
  251. */
  252. function system_theme_suggestions_maintenance_page(array $variables) {
  253. $suggestions = array();
  254. // Dead databases will show error messages so supplying this template will
  255. // allow themers to override the page and the content completely.
  256. $offline = defined('MAINTENANCE_MODE');
  257. try {
  258. \Drupal::service('path.matcher')->isFrontPage();
  259. }
  260. catch (Exception $e) {
  261. // The database is not yet available.
  262. $offline = TRUE;
  263. }
  264. if ($offline) {
  265. $suggestions[] = 'maintenance_page__offline';
  266. }
  267. return $suggestions;
  268. }
  269. /**
  270. * Implements hook_theme_suggestions_HOOK().
  271. */
  272. function system_theme_suggestions_region(array $variables) {
  273. $suggestions = array();
  274. if (!empty($variables['elements']['#region'])) {
  275. $suggestions[] = 'region__' . $variables['elements']['#region'];
  276. }
  277. return $suggestions;
  278. }
  279. /**
  280. * Implements hook_theme_suggestions_HOOK().
  281. */
  282. function system_theme_suggestions_field(array $variables) {
  283. $suggestions = array();
  284. $element = $variables['element'];
  285. $suggestions[] = 'field__' . $element['#field_type'];
  286. $suggestions[] = 'field__' . $element['#field_name'];
  287. $suggestions[] = 'field__' . $element['#entity_type'] . '__' . $element['#bundle'];
  288. $suggestions[] = 'field__' . $element['#entity_type'] . '__' . $element['#field_name'];
  289. $suggestions[] = 'field__' . $element['#entity_type'] . '__' . $element['#field_name'] . '__' . $element['#bundle'];
  290. return $suggestions;
  291. }
  292. /**
  293. * Prepares variables for the list of available bundles.
  294. *
  295. * Default template: entity-add-list.html.twig.
  296. *
  297. * @param array $variables
  298. * An associative array containing:
  299. * - bundles: An array of bundles with the label, description, add_link keys.
  300. * - add_bundle_message: The message shown when there are no bundles. Only
  301. * available if the entity type uses bundle entities.
  302. */
  303. function template_preprocess_entity_add_list(&$variables) {
  304. foreach ($variables['bundles'] as $bundle_name => $bundle_info) {
  305. $variables['bundles'][$bundle_name]['description'] = [
  306. '#markup' => $bundle_info['description'],
  307. ];
  308. }
  309. }
  310. /**
  311. * @defgroup authorize Authorized operations
  312. * @{
  313. * Functions to run operations with elevated privileges via authorize.php.
  314. *
  315. * Because of the Update manager functionality included in Drupal core, there
  316. * is a mechanism for running operations with elevated file system privileges,
  317. * the top-level authorize.php script. This script runs at a reduced Drupal
  318. * bootstrap level so that it is not reliant on the entire site being
  319. * functional. The operations use a FileTransfer class to manipulate code
  320. * installed on the system as the user that owns the files, not the user that
  321. * the httpd is running as.
  322. *
  323. * The first setup is to define a callback function that should be authorized
  324. * to run with the elevated privileges. This callback should take a
  325. * FileTransfer as its first argument, although you can define an array of
  326. * other arguments it should be invoked with. The callback should be placed in
  327. * a separate .inc file that will be included by authorize.php.
  328. *
  329. * To run the operation, certain data must be saved into the SESSION, and then
  330. * the flow of control should be redirected to the authorize.php script. There
  331. * are two ways to do this, either to call system_authorized_run() directly,
  332. * or to call system_authorized_init() and then redirect to authorize.php,
  333. * using the URL from system_authorized_get_url(). Redirecting yourself is
  334. * necessary when your authorized operation is being triggered by a form
  335. * submit handler, since calling redirecting in a submit handler is a bad
  336. * idea, and you should instead use $form_state->setRedirect().
  337. *
  338. * Once the SESSION is setup for the operation and the user is redirected to
  339. * authorize.php, they will be prompted for their connection credentials (core
  340. * provides FTP and SSH by default, although other connection classes can be
  341. * added via contributed modules). With valid credentials, authorize.php will
  342. * instantiate the appropriate FileTransfer object, and then invoke the
  343. * desired operation passing in that object. The authorize.php script can act
  344. * as a Batch API processing page, if the operation requires a batch.
  345. *
  346. * @see authorize.php
  347. * @see \Drupal\Core\FileTransfer\FileTransfer
  348. * @see hook_filetransfer_info()
  349. */
  350. /**
  351. * Setup a given callback to run via authorize.php with elevated privileges.
  352. *
  353. * To use authorize.php, certain variables must be stashed into $_SESSION. This
  354. * function sets up all the necessary $_SESSION variables. The calling function
  355. * should then redirect to authorize.php, using the full path returned by
  356. * system_authorized_get_url(). That initiates the workflow that will eventually
  357. * lead to the callback being invoked. The callback will be invoked at a low
  358. * bootstrap level, without all modules being invoked, so it needs to be careful
  359. * not to assume any code exists. Example (system_authorized_run()):
  360. * @code
  361. * system_authorized_init($callback, $file, $arguments, $page_title);
  362. * return new RedirectResponse(system_authorized_get_url()->toString());
  363. * @endcode
  364. * Example (update_manager_install_form_submit()):
  365. * @code
  366. * system_authorized_init('update_authorize_run_install',
  367. * drupal_get_path('module', 'update') . '/update.authorize.inc',
  368. * $arguments, t('Update manager'));
  369. * $form_state->setRedirectUrl(system_authorized_get_url());
  370. * @endcode
  371. *
  372. * @param $callback
  373. * The name of the function to invoke once the user authorizes the operation.
  374. * @param $file
  375. * The full path to the file where the callback function is implemented.
  376. * @param $arguments
  377. * Optional array of arguments to pass into the callback when it is invoked.
  378. * Note that the first argument to the callback is always the FileTransfer
  379. * object created by authorize.php when the user authorizes the operation.
  380. * @param $page_title
  381. * Optional string to use as the page title once redirected to authorize.php.
  382. * @return
  383. * Nothing, this function just initializes variables in the user's session.
  384. */
  385. function system_authorized_init($callback, $file, $arguments = array(), $page_title = NULL) {
  386. // First, figure out what file transfer backends the site supports, and put
  387. // all of those in the SESSION so that authorize.php has access to all of
  388. // them via the class autoloader, even without a full bootstrap.
  389. $_SESSION['authorize_filetransfer_info'] = drupal_get_filetransfer_info();
  390. // Now, define the callback to invoke.
  391. $_SESSION['authorize_operation'] = array(
  392. 'callback' => $callback,
  393. 'file' => $file,
  394. 'arguments' => $arguments,
  395. );
  396. if (isset($page_title)) {
  397. $_SESSION['authorize_page_title'] = $page_title;
  398. }
  399. }
  400. /**
  401. * Return the URL for the authorize.php script.
  402. *
  403. * @param array $options
  404. * Optional array of options to set on the \Drupal\Core\Url object.
  405. * @return \Drupal\Core\Url
  406. * The full URL to authorize.php, using HTTPS if available.
  407. *
  408. * @see system_authorized_init()
  409. */
  410. function system_authorized_get_url(array $options = array()) {
  411. // core/authorize.php is an unrouted URL, so using the base: scheme is
  412. // the correct usage for this case.
  413. $url = Url::fromUri('base:core/authorize.php');
  414. $url_options = $url->getOptions();
  415. $url->setOptions($options + $url_options);
  416. return $url;
  417. }
  418. /**
  419. * Returns the URL for the authorize.php script when it is processing a batch.
  420. *
  421. * @param array $options
  422. * Optional array of options to set on the \Drupal\Core\Url object.
  423. *
  424. * @return \Drupal\Core\Url
  425. */
  426. function system_authorized_batch_processing_url(array $options = array()) {
  427. $options['query'] = array('batch' => '1');
  428. return system_authorized_get_url($options);
  429. }
  430. /**
  431. * Setup and invoke an operation using authorize.php.
  432. *
  433. * @see system_authorized_init()
  434. */
  435. function system_authorized_run($callback, $file, $arguments = array(), $page_title = NULL) {
  436. system_authorized_init($callback, $file, $arguments, $page_title);
  437. return new RedirectResponse(system_authorized_get_url()->toString());
  438. }
  439. /**
  440. * Use authorize.php to run batch_process().
  441. *
  442. * @see batch_process()
  443. */
  444. function system_authorized_batch_process() {
  445. $finish_url = system_authorized_get_url();
  446. $process_url = system_authorized_batch_processing_url();
  447. return batch_process($finish_url->setAbsolute()->toString(), $process_url);
  448. }
  449. /**
  450. * @} End of "defgroup authorize".
  451. */
  452. /**
  453. * Implements hook_updater_info().
  454. */
  455. function system_updater_info() {
  456. return array(
  457. 'module' => array(
  458. 'class' => 'Drupal\Core\Updater\Module',
  459. 'name' => t('Update modules'),
  460. 'weight' => 0,
  461. ),
  462. 'theme' => array(
  463. 'class' => 'Drupal\Core\Updater\Theme',
  464. 'name' => t('Update themes'),
  465. 'weight' => 0,
  466. ),
  467. );
  468. }
  469. /**
  470. * Implements hook_filetransfer_info().
  471. */
  472. function system_filetransfer_info() {
  473. $backends = array();
  474. // This is the default, will be available on most systems.
  475. if (function_exists('ftp_connect')) {
  476. $backends['ftp'] = array(
  477. 'title' => t('FTP'),
  478. 'class' => 'Drupal\Core\FileTransfer\FTP',
  479. 'weight' => 0,
  480. );
  481. }
  482. // SSH2 lib connection is only available if the proper PHP extension is
  483. // installed.
  484. if (function_exists('ssh2_connect')) {
  485. $backends['ssh'] = array(
  486. 'title' => t('SSH'),
  487. 'class' => 'Drupal\Core\FileTransfer\SSH',
  488. 'weight' => 20,
  489. );
  490. }
  491. return $backends;
  492. }
  493. /**
  494. * Implements hook_page_attachments().
  495. *
  496. * @see template_preprocess_maintenance_page()
  497. * @see \Drupal\Core\EventSubscriber\ActiveLinkResponseFilter
  498. */
  499. function system_page_attachments(array &$page) {
  500. // Ensure the same CSS is loaded in template_preprocess_maintenance_page().
  501. $page['#attached']['library'][] = 'system/base';
  502. if (\Drupal::service('router.admin_context')->isAdminRoute()) {
  503. $page['#attached']['library'][] = 'system/admin';
  504. }
  505. // Attach libraries used by this theme.
  506. $active_theme = \Drupal::theme()->getActiveTheme();
  507. foreach ($active_theme->getLibraries() as $library) {
  508. $page['#attached']['library'][] = $library;
  509. }
  510. // Attach favicon.
  511. if (theme_get_setting('features.favicon')) {
  512. $favicon = theme_get_setting('favicon.url');
  513. $type = theme_get_setting('favicon.mimetype');
  514. $page['#attached']['html_head_link'][][] = array(
  515. 'rel' => 'shortcut icon',
  516. 'href' => UrlHelper::stripDangerousProtocols($favicon),
  517. 'type' => $type,
  518. );
  519. }
  520. // Get the major Drupal version.
  521. list($version, ) = explode('.', \Drupal::VERSION);
  522. // Attach default meta tags.
  523. $meta_default = array(
  524. // Make sure the Content-Type comes first because the IE browser may be
  525. // vulnerable to XSS via encoding attacks from any content that comes
  526. // before this META tag, such as a TITLE tag.
  527. 'system_meta_content_type' => array(
  528. '#tag' => 'meta',
  529. '#attributes' => array(
  530. 'charset' => 'utf-8',
  531. ),
  532. // Security: This always has to be output first.
  533. '#weight' => -1000,
  534. ),
  535. // Show Drupal and the major version number in the META GENERATOR tag.
  536. 'system_meta_generator' => array(
  537. '#type' => 'html_tag',
  538. '#tag' => 'meta',
  539. '#attributes' => array(
  540. 'name' => 'Generator',
  541. 'content' => 'Drupal ' . $version . ' (https://www.drupal.org)',
  542. ),
  543. ),
  544. // Attach default mobile meta tags for responsive design.
  545. 'MobileOptimized' => array(
  546. '#tag' => 'meta',
  547. '#attributes' => array(
  548. 'name' => 'MobileOptimized',
  549. 'content' => 'width',
  550. ),
  551. ),
  552. 'HandheldFriendly' => array(
  553. '#tag' => 'meta',
  554. '#attributes' => array(
  555. 'name' => 'HandheldFriendly',
  556. 'content' => 'true',
  557. ),
  558. ),
  559. 'viewport' => array(
  560. '#tag' => 'meta',
  561. '#attributes' => array(
  562. 'name' => 'viewport',
  563. 'content' => 'width=device-width, initial-scale=1.0',
  564. ),
  565. ),
  566. );
  567. foreach ($meta_default as $key => $value) {
  568. $page['#attached']['html_head'][] = [$value, $key];
  569. }
  570. // Handle setting the "active" class on links by:
  571. // - loading the active-link library if the current user is authenticated;
  572. // - applying a response filter if the current user is anonymous.
  573. // @see \Drupal\Core\Link
  574. // @see \Drupal\Core\Utility\LinkGenerator::generate()
  575. // @see template_preprocess_links()
  576. // @see \Drupal\Core\EventSubscriber\ActiveLinkResponseFilter
  577. if (\Drupal::currentUser()->isAuthenticated()) {
  578. $page['#attached']['library'][] = 'core/drupal.active-link';
  579. }
  580. }
  581. /**
  582. * Implements hook_js_settings_build().
  583. *
  584. * Sets values for the core/drupal.ajax library, which just depends on the
  585. * active theme but no other request-dependent values.
  586. */
  587. function system_js_settings_build(&$settings, AttachedAssetsInterface $assets) {
  588. // Generate the values for the core/drupal.ajax library.
  589. // We need to send ajaxPageState settings for core/drupal.ajax if:
  590. // - ajaxPageState is being loaded in this Response, in which case it will
  591. // already exist at $settings['ajaxPageState'] (because the core/drupal.ajax
  592. // library definition specifies a placeholder 'ajaxPageState' setting).
  593. // - core/drupal.ajax already has been loaded and hence this is an AJAX
  594. // Response in which we must send the list of extra asset libraries that are
  595. // being added in this AJAX Response.
  596. /** @var \Drupal\Core\Asset\LibraryDependencyResolver $library_dependency_resolver */
  597. $library_dependency_resolver = \Drupal::service('library.dependency_resolver');
  598. if (isset($settings['ajaxPageState']) || in_array('core/drupal.ajax', $library_dependency_resolver->getLibrariesWithDependencies($assets->getAlreadyLoadedLibraries()))) {
  599. // Provide the page with information about the theme that's used, so that
  600. // a later AJAX request can be rendered using the same theme.
  601. // @see \Drupal\Core\Theme\AjaxBasePageNegotiator
  602. $theme_key = \Drupal::theme()->getActiveTheme()->getName();
  603. $settings['ajaxPageState']['theme'] = $theme_key;
  604. }
  605. }
  606. /**
  607. * Implements hook_js_settings_alter().
  608. *
  609. * Sets values which depend on the current request, like core/drupalSettings
  610. * as well as theme_token ajax state.
  611. */
  612. function system_js_settings_alter(&$settings, AttachedAssetsInterface $assets) {
  613. // As this is being output in the final response always use the master
  614. // request.
  615. $request = \Drupal::requestStack()->getMasterRequest();
  616. $current_query = $request->query->all();
  617. // Let output path processors set a prefix.
  618. /** @var \Drupal\Core\PathProcessor\OutboundPathProcessorInterface $path_processor */
  619. $path_processor = \Drupal::service('path_processor_manager');
  620. $options = ['prefix' => ''];
  621. $path_processor->processOutbound('/', $options);
  622. $pathPrefix = $options['prefix'];
  623. $route_match = \Drupal::routeMatch();
  624. if ($route_match instanceof StackedRouteMatchInterface) {
  625. $route_match = $route_match->getMasterRouteMatch();
  626. }
  627. $current_path = $route_match->getRouteName() ? Url::fromRouteMatch($route_match)->getInternalPath() : '';
  628. $current_path_is_admin = \Drupal::service('router.admin_context')->isAdminRoute($route_match->getRouteObject());
  629. $path_settings = [
  630. 'baseUrl' => $request->getBaseUrl() . '/',
  631. 'pathPrefix' => $pathPrefix,
  632. 'currentPath' => $current_path,
  633. 'currentPathIsAdmin' => $current_path_is_admin,
  634. 'isFront' => \Drupal::service('path.matcher')->isFrontPage(),
  635. 'currentLanguage' => \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId(),
  636. ];
  637. if (!empty($current_query)) {
  638. ksort($current_query);
  639. $path_settings['currentQuery'] = (object) $current_query;
  640. }
  641. // Only set core/drupalSettings values that haven't been set already.
  642. foreach ($path_settings as $key => $value) {
  643. if (!isset($settings['path'][$key])) {
  644. $settings['path'][$key] = $value;
  645. }
  646. }
  647. if (!isset($settings['pluralDelimiter'])) {
  648. $settings['pluralDelimiter'] = LOCALE_PLURAL_DELIMITER;
  649. }
  650. // Add the theme token to ajaxPageState, ensuring the database is available
  651. // before doing so. Also add the loaded libraries to ajaxPageState.
  652. /** @var \Drupal\Core\Asset\LibraryDependencyResolver $library_dependency_resolver */
  653. $library_dependency_resolver = \Drupal::service('library.dependency_resolver');
  654. if (isset($settings['ajaxPageState']) || in_array('core/drupal.ajax', $library_dependency_resolver->getLibrariesWithDependencies($assets->getAlreadyLoadedLibraries()))) {
  655. if (!defined('MAINTENANCE_MODE')) {
  656. // The theme token is only validated when the theme requested is not the
  657. // default, so don't generate it unless necessary.
  658. // @see \Drupal\Core\Theme\AjaxBasePageNegotiator::determineActiveTheme()
  659. $active_theme_key = \Drupal::theme()->getActiveTheme()->getName();
  660. if ($active_theme_key !== \Drupal::service('theme_handler')->getDefault()) {
  661. $settings['ajaxPageState']['theme_token'] = \Drupal::csrfToken()
  662. ->get($active_theme_key);
  663. }
  664. }
  665. // Provide the page with information about the individual asset libraries
  666. // used, information not otherwise available when aggregation is enabled.
  667. $minimal_libraries = $library_dependency_resolver->getMinimalRepresentativeSubset(array_merge(
  668. $assets->getLibraries(),
  669. $assets->getAlreadyLoadedLibraries()
  670. ));
  671. sort($minimal_libraries);
  672. $settings['ajaxPageState']['libraries'] = implode(',', $minimal_libraries);
  673. }
  674. }
  675. /**
  676. * Implements hook_form_alter().
  677. */
  678. function system_form_alter(&$form, FormStateInterface $form_state) {
  679. // If the page that's being built is cacheable, set the 'immutable' flag, to
  680. // ensure that when the form is used, a new form build ID is generated when
  681. // appropriate, to prevent information disclosure.
  682. // Note: This code just wants to know whether cache response headers are set,
  683. // not whether page_cache module will be active.
  684. // \Drupal\Core\EventSubscriber\FinishResponseSubscriber::onRespond will
  685. // send those headers, in case $request_policy->check($request) succeeds. In
  686. // that case we need to ensure that the immutable flag is sot, so future POST
  687. // request won't take over the form state of another user.
  688. /** @var \Drupal\Core\PageCache\RequestPolicyInterface $request_policy */
  689. $request_policy = \Drupal::service('page_cache_request_policy');
  690. $request = \Drupal::requestStack()->getCurrentRequest();
  691. $request_is_cacheable = $request_policy->check($request) === RequestPolicyInterface::ALLOW;
  692. if ($request_is_cacheable) {
  693. $form_state->addBuildInfo('immutable', TRUE);
  694. }
  695. }
  696. /**
  697. * Implements hook_form_FORM_ID_alter() for \Drupal\user\AccountForm.
  698. */
  699. function system_form_user_form_alter(&$form, FormStateInterface $form_state) {
  700. if (\Drupal::config('system.date')->get('timezone.user.configurable')) {
  701. system_user_timezone($form, $form_state);
  702. }
  703. }
  704. /**
  705. * Implements hook_form_FORM_ID_alter() for \Drupal\user\RegisterForm.
  706. */
  707. function system_form_user_register_form_alter(&$form, FormStateInterface $form_state) {
  708. $config = \Drupal::config('system.date');
  709. if ($config->get('timezone.user.configurable') && $config->get('timezone.user.default') == DRUPAL_USER_TIMEZONE_SELECT) {
  710. system_user_timezone($form, $form_state);
  711. }
  712. }
  713. /**
  714. * Implements hook_ENTITY_TYPE_presave() for user entities.
  715. */
  716. function system_user_presave(UserInterface $account) {
  717. $config = \Drupal::config('system.date');
  718. if ($config->get('timezone.user.configurable') && !$account->getTimeZone() && !$config->get('timezone.user.default')) {
  719. $account->timezone = $config->get('timezone.default');
  720. }
  721. }
  722. /**
  723. * Implements hook_user_login().
  724. */
  725. function system_user_login(UserInterface $account) {
  726. $config = \Drupal::config('system.date');
  727. // If the user has a NULL time zone, notify them to set a time zone.
  728. if (!$account->getTimezone() && $config->get('timezone.user.configurable') && $config->get('timezone.user.warn')) {
  729. drupal_set_message(t('Configure your <a href=":user-edit">account time zone setting</a>.', array(':user-edit' => $account->url('edit-form', array('query' => \Drupal::destination()->getAsArray(), 'fragment' => 'edit-timezone')))));
  730. }
  731. }
  732. /**
  733. * Add the time zone field to the user edit and register forms.
  734. */
  735. function system_user_timezone(&$form, FormStateInterface $form_state) {
  736. $user = \Drupal::currentUser();
  737. $account = $form_state->getFormObject()->getEntity();
  738. $form['timezone'] = array(
  739. '#type' => 'details',
  740. '#title' => t('Locale settings'),
  741. '#open' => TRUE,
  742. '#weight' => 6,
  743. );
  744. $form['timezone']['timezone'] = array(
  745. '#type' => 'select',
  746. '#title' => t('Time zone'),
  747. '#default_value' => $account->getTimezone() ? $account->getTimezone() : \Drupal::config('system.date')->get('timezone.default'),
  748. '#options' => system_time_zones($account->id() != $user->id()),
  749. '#description' => t('Select the desired local time and time zone. Dates and times throughout this site will be displayed using this time zone.'),
  750. );
  751. $user_input = $form_state->getUserInput();
  752. if (!$account->getTimezone() && $account->id() == $user->id() && empty($user_input['timezone'])) {
  753. $form['timezone']['#attached']['library'][] = 'core/drupal.timezone';
  754. $form['timezone']['timezone']['#attributes'] = array('class' => array('timezone-detect'));
  755. }
  756. }
  757. /**
  758. * Implements hook_preprocess_HOOK() for block templates.
  759. */
  760. function system_preprocess_block(&$variables) {
  761. switch ($variables['base_plugin_id']) {
  762. case 'system_branding_block':
  763. $variables['site_logo'] = '';
  764. if ($variables['content']['site_logo']['#access'] && $variables['content']['site_logo']['#uri']) {
  765. $variables['site_logo'] = $variables['content']['site_logo']['#uri'];
  766. }
  767. $variables['site_name'] = '';
  768. if ($variables['content']['site_name']['#access'] && $variables['content']['site_name']['#markup']) {
  769. $variables['site_name'] = $variables['content']['site_name']['#markup'];
  770. }
  771. $variables['site_slogan'] = '';
  772. if ($variables['content']['site_slogan']['#access'] && $variables['content']['site_slogan']['#markup']) {
  773. $variables['site_slogan'] = [
  774. '#markup' => $variables['content']['site_slogan']['#markup'],
  775. ];
  776. }
  777. break;
  778. case 'system_powered_by_block':
  779. $variables['attributes']['role'] = 'complementary';
  780. break;
  781. }
  782. }
  783. /**
  784. * Checks the existence of the directory specified in $form_element.
  785. *
  786. * This function is called from the system_settings form to check all core
  787. * file directories (file_public_path, file_private_path, file_temporary_path).
  788. *
  789. * @param $form_element
  790. * The form element containing the name of the directory to check.
  791. * @param \Drupal\Core\Form\FormStateInterface $form_state
  792. * The current state of the form.
  793. */
  794. function system_check_directory($form_element, FormStateInterface $form_state) {
  795. $directory = $form_element['#value'];
  796. if (strlen($directory) == 0) {
  797. return $form_element;
  798. }
  799. $logger = \Drupal::logger('file system');
  800. if (!is_dir($directory) && !drupal_mkdir($directory, NULL, TRUE)) {
  801. // If the directory does not exists and cannot be created.
  802. $form_state->setErrorByName($form_element['#parents'][0], t('The directory %directory does not exist and could not be created.', array('%directory' => $directory)));
  803. $logger->error('The directory %directory does not exist and could not be created.', array('%directory' => $directory));
  804. }
  805. if (is_dir($directory) && !is_writable($directory) && !drupal_chmod($directory)) {
  806. // If the directory is not writable and cannot be made so.
  807. $form_state->setErrorByName($form_element['#parents'][0], t('The directory %directory exists but is not writable and could not be made writable.', array('%directory' => $directory)));
  808. $logger->error('The directory %directory exists but is not writable and could not be made writable.', array('%directory' => $directory));
  809. }
  810. elseif (is_dir($directory)) {
  811. if ($form_element['#name'] == 'file_public_path') {
  812. // Create public .htaccess file.
  813. file_save_htaccess($directory, FALSE);
  814. }
  815. else {
  816. // Create private .htaccess file.
  817. file_save_htaccess($directory);
  818. }
  819. }
  820. return $form_element;
  821. }
  822. /**
  823. * Returns an array of information about enabled modules or themes.
  824. *
  825. * This function returns the contents of the .info.yml file for each installed
  826. * module or theme.
  827. *
  828. * @param $type
  829. * Either 'module' or 'theme'.
  830. * @param $name
  831. * (optional) The name of a module or theme whose information shall be
  832. * returned. If omitted, all records for the provided $type will be returned.
  833. * If $name does not exist in the provided $type or is not enabled, an empty
  834. * array will be returned.
  835. *
  836. * @return
  837. * An associative array of module or theme information keyed by name, or only
  838. * information for $name, if given. If no records are available, an empty
  839. * array is returned.
  840. *
  841. * @see system_rebuild_module_data()
  842. * @see \Drupal\Core\Extension\ThemeHandlerInterface::rebuildThemeData()
  843. */
  844. function system_get_info($type, $name = NULL) {
  845. if ($type == 'module') {
  846. $info = &drupal_static(__FUNCTION__);
  847. if (!isset($info)) {
  848. if ($cache = \Drupal::cache()->get('system.module.info')) {
  849. $info = $cache->data;
  850. }
  851. else {
  852. $data = system_rebuild_module_data();
  853. foreach (\Drupal::moduleHandler()->getModuleList() as $module => $filename) {
  854. if (isset($data[$module])) {
  855. $info[$module] = $data[$module]->info;
  856. }
  857. }
  858. // Store the module information in cache. This cache is cleared by
  859. // calling system_rebuild_module_data(), for example, when listing
  860. // modules, (un)installing modules, importing configuration, updating
  861. // the site and when flushing all the caches.
  862. \Drupal::cache()->set('system.module.info', $info);
  863. }
  864. }
  865. }
  866. else {
  867. $info = array();
  868. $list = system_list($type);
  869. foreach ($list as $shortname => $item) {
  870. if (!empty($item->status)) {
  871. $info[$shortname] = $item->info;
  872. }
  873. }
  874. }
  875. if (isset($name)) {
  876. return isset($info[$name]) ? $info[$name] : array();
  877. }
  878. return $info;
  879. }
  880. /**
  881. * Helper function to scan and collect module .info.yml data.
  882. *
  883. * @return \Drupal\Core\Extension\Extension[]
  884. * An associative array of module information.
  885. */
  886. function _system_rebuild_module_data() {
  887. $listing = new ExtensionDiscovery(\Drupal::root());
  888. // Find installation profiles. This needs to happen before performing a
  889. // module scan as the module scan requires knowing what the active profile is.
  890. // @todo Remove as part of https://www.drupal.org/node/2186491.
  891. $profiles = $listing->scan('profile');
  892. $profile = drupal_get_profile();
  893. if ($profile && isset($profiles[$profile])) {
  894. // Prime the drupal_get_filename() static cache with the profile info file
  895. // location so we can use drupal_get_path() on the active profile during
  896. // the module scan.
  897. // @todo Remove as part of https://www.drupal.org/node/2186491.
  898. drupal_get_filename('profile', $profile, $profiles[$profile]->getPathname());
  899. }
  900. // Find modules.
  901. $modules = $listing->scan('module');
  902. // Include the installation profile in modules that are loaded.
  903. if ($profile) {
  904. $modules[$profile] = $profiles[$profile];
  905. // Installation profile hooks are always executed last.
  906. $modules[$profile]->weight = 1000;
  907. }
  908. // Set defaults for module info.
  909. $defaults = array(
  910. 'dependencies' => array(),
  911. 'description' => '',
  912. 'package' => 'Other',
  913. 'version' => NULL,
  914. 'php' => DRUPAL_MINIMUM_PHP,
  915. );
  916. // Read info files for each module.
  917. foreach ($modules as $key => $module) {
  918. // Look for the info file.
  919. $module->info = \Drupal::service('info_parser')->parse($module->getPathname());
  920. // Add the info file modification time, so it becomes available for
  921. // contributed modules to use for ordering module lists.
  922. $module->info['mtime'] = $module->getMTime();
  923. // Merge in defaults and save.
  924. $modules[$key]->info = $module->info + $defaults;
  925. // Installation profiles are hidden by default, unless explicitly specified
  926. // otherwise in the .info.yml file.
  927. if ($key == $profile && !isset($modules[$key]->info['hidden'])) {
  928. $modules[$key]->info['hidden'] = TRUE;
  929. }
  930. // Invoke hook_system_info_alter() to give installed modules a chance to
  931. // modify the data in the .info.yml files if necessary.
  932. // @todo Remove $type argument, obsolete with $module->getType().
  933. $type = 'module';
  934. \Drupal::moduleHandler()->alter('system_info', $modules[$key]->info, $modules[$key], $type);
  935. }
  936. // It is possible that a module was marked as required by
  937. // hook_system_info_alter() and modules that it depends on are not required.
  938. foreach ($modules as $module) {
  939. _system_rebuild_module_data_ensure_required($module, $modules);
  940. }
  941. if ($profile && isset($modules[$profile])) {
  942. // The installation profile is required, if it's a valid module.
  943. $modules[$profile]->info['required'] = TRUE;
  944. // Add a default distribution name if the profile did not provide one.
  945. // @see install_profile_info()
  946. // @see drupal_install_profile_distribution_name()
  947. if (!isset($modules[$profile]->info['distribution']['name'])) {
  948. $modules[$profile]->info['distribution']['name'] = 'Drupal';
  949. }
  950. }
  951. return $modules;
  952. }
  953. /**
  954. * Ensures that dependencies of required modules are also required.
  955. *
  956. * @param \Drupal\Core\Extension\Extension $module
  957. * The module info.
  958. * @param \Drupal\Core\Extension\Extension[] $modules
  959. * The array of all module info.
  960. */
  961. function _system_rebuild_module_data_ensure_required($module, &$modules) {
  962. if (!empty($module->info['required'])) {
  963. foreach ($module->info['dependencies'] as $dependency) {
  964. $dependency_name = ModuleHandler::parseDependency($dependency)['name'];
  965. if (!isset($modules[$dependency_name]->info['required'])) {
  966. $modules[$dependency_name]->info['required'] = TRUE;
  967. $modules[$dependency_name]->info['explanation'] = t('Dependency of required module @module', array('@module' => $module->info['name']));
  968. // Ensure any dependencies it has are required.
  969. _system_rebuild_module_data_ensure_required($modules[$dependency_name], $modules);
  970. }
  971. }
  972. }
  973. }
  974. /**
  975. * Rebuild, save, and return data about all currently available modules.
  976. *
  977. * @return \Drupal\Core\Extension\Extension[]
  978. * Array of all available modules and their data.
  979. */
  980. function system_rebuild_module_data() {
  981. $modules_cache = &drupal_static(__FUNCTION__);
  982. // Only rebuild once per request. $modules and $modules_cache cannot be
  983. // combined into one variable, because the $modules_cache variable is reset by
  984. // reference from system_list_reset() during the rebuild.
  985. if (!isset($modules_cache)) {
  986. $modules = _system_rebuild_module_data();
  987. $files = array();
  988. ksort($modules);
  989. // Add status, weight, and schema version.
  990. $installed_modules = \Drupal::config('core.extension')->get('module') ?: array();
  991. foreach ($modules as $name => $module) {
  992. $module->weight = isset($installed_modules[$name]) ? $installed_modules[$name] : 0;
  993. $module->status = (int) isset($installed_modules[$name]);
  994. $module->schema_version = SCHEMA_UNINSTALLED;
  995. $files[$name] = $module->getPathname();
  996. }
  997. $modules = \Drupal::moduleHandler()->buildModuleDependencies($modules);
  998. $modules_cache = $modules;
  999. // Store filenames to allow drupal_get_filename() to retrieve them without
  1000. // having to rebuild or scan the filesystem.
  1001. \Drupal::state()->set('system.module.files', $files);
  1002. // Clear the module info cache.
  1003. \Drupal::cache()->delete('system.module.info');
  1004. drupal_static_reset('system_get_info');
  1005. }
  1006. return $modules_cache;
  1007. }
  1008. /**
  1009. * Get a list of available regions from a specified theme.
  1010. *
  1011. * @param \Drupal\Core\Extension\Extension|string $theme
  1012. * A theme extension object, or the name of a theme.
  1013. * @param $show
  1014. * Possible values: REGIONS_ALL or REGIONS_VISIBLE. Visible excludes hidden
  1015. * regions.
  1016. * @return
  1017. * An array of regions in the form $region['name'] = 'description'.
  1018. */
  1019. function system_region_list($theme, $show = REGIONS_ALL) {
  1020. if (!$theme instanceof Extension) {
  1021. $themes = \Drupal::service('theme_handler')->listInfo();
  1022. if (!isset($themes[$theme])) {
  1023. return array();
  1024. }
  1025. $theme = $themes[$theme];
  1026. }
  1027. $list = array();
  1028. $info = $theme->info;
  1029. // If requested, suppress hidden regions. See block_admin_display_form().
  1030. foreach ($info['regions'] as $name => $label) {
  1031. if ($show == REGIONS_ALL || !isset($info['regions_hidden']) || !in_array($name, $info['regions_hidden'])) {
  1032. $list[$name] = t($label);
  1033. }
  1034. }
  1035. return $list;
  1036. }
  1037. /**
  1038. * Array sorting callback; sorts modules by their name.
  1039. */
  1040. function system_sort_modules_by_info_name($a, $b) {
  1041. return strcasecmp($a->info['name'], $b->info['name']);
  1042. }
  1043. /**
  1044. * Sorts themes by their names, with the default theme listed first.
  1045. *
  1046. * Callback for uasort() within
  1047. * \Drupal\system\Controller\SystemController::themesPage().
  1048. *
  1049. * @see system_sort_modules_by_info_name()
  1050. */
  1051. function system_sort_themes($a, $b) {
  1052. if ($a->is_default) {
  1053. return -1;
  1054. }
  1055. if ($b->is_default) {
  1056. return 1;
  1057. }
  1058. return strcasecmp($a->info['name'], $b->info['name']);
  1059. }
  1060. /**
  1061. * Implements hook_system_info_alter().
  1062. */
  1063. function system_system_info_alter(&$info, Extension $file, $type) {
  1064. // Remove page-top and page-bottom from the blocks UI since they are reserved for
  1065. // modules to populate from outside the blocks system.
  1066. if ($type == 'theme') {
  1067. $info['regions_hidden'][] = 'page_top';
  1068. $info['regions_hidden'][] = 'page_bottom';
  1069. }
  1070. }
  1071. /**
  1072. * Gets the name of the default region for a given theme.
  1073. *
  1074. * @param $theme
  1075. * The name of a theme.
  1076. * @return
  1077. * A string that is the region name.
  1078. */
  1079. function system_default_region($theme) {
  1080. $regions = array_keys(system_region_list($theme, REGIONS_VISIBLE));
  1081. return isset($regions[0]) ? $regions[0] : '';
  1082. }
  1083. /**
  1084. * Determines whether the current user is in compact mode.
  1085. *
  1086. * Compact mode shows certain administration pages with less description text,
  1087. * such as the configuration page and the permissions page.
  1088. *
  1089. * Whether the user is in compact mode is determined by a cookie, which is set
  1090. * for the user by \Drupal\system\Controller\SystemController::compactPage().
  1091. *
  1092. * If the user does not have the cookie, the default value is given by the
  1093. * configuration variable 'system.site.admin_compact_mode', which itself
  1094. * defaults to FALSE. This does not have a user interface to set it: it is a
  1095. * hidden variable which can be set in the settings.php file.
  1096. *
  1097. * @return bool
  1098. * TRUE when in compact mode, FALSE when in expanded mode.
  1099. */
  1100. function system_admin_compact_mode() {
  1101. // PHP converts dots into underscores in cookie names to avoid problems with
  1102. // its parser, so we use a converted cookie name.
  1103. return \Drupal::request()->cookies->get('Drupal_visitor_admin_compact_mode', \Drupal::config('system.site')->get('admin_compact_mode'));
  1104. }
  1105. /**
  1106. * Generate a list of tasks offered by a specified module.
  1107. *
  1108. * @param string $module
  1109. * Module name.
  1110. * @param array $info
  1111. * The module's information, as provided by system_get_info().
  1112. *
  1113. * @return array
  1114. * An array of task links.
  1115. */
  1116. function system_get_module_admin_tasks($module, array $info) {
  1117. $tree = &drupal_static(__FUNCTION__);
  1118. $menu_tree = \Drupal::menuTree();
  1119. if (!isset($tree)) {
  1120. $parameters = new MenuTreeParameters();
  1121. $parameters->setRoot('system.admin')->excludeRoot()->onlyEnabledLinks();
  1122. $tree = $menu_tree->load('system.admin', $parameters);
  1123. $manipulators = array(
  1124. array('callable' => 'menu.default_tree_manipulators:checkAccess'),
  1125. array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
  1126. array('callable' => 'menu.default_tree_manipulators:flatten'),
  1127. );
  1128. $tree = $menu_tree->transform($tree, $manipulators);
  1129. }
  1130. $admin_tasks = array();
  1131. foreach ($tree as $element) {
  1132. if (!$element->access->isAllowed()) {
  1133. // @todo Bubble cacheability metadata of both accessible and inaccessible
  1134. // links. Currently made impossible by the way admin tasks are rendered.
  1135. continue;
  1136. }
  1137. $link = $element->link;
  1138. if ($link->getProvider() != $module) {
  1139. continue;
  1140. }
  1141. $admin_tasks[] = array(
  1142. 'title' => $link->getTitle(),
  1143. 'description' => $link->getDescription(),
  1144. 'url' => $link->getUrlObject(),
  1145. );
  1146. }
  1147. // Append link for permissions.
  1148. /** @var \Drupal\user\PermissionHandlerInterface $permission_handler */
  1149. $permission_handler = \Drupal::service('user.permissions');
  1150. if ($permission_handler->moduleProvidesPermissions($module)) {
  1151. /** @var \Drupal\Core\Access\AccessManagerInterface $access_manager */
  1152. $access_manager = \Drupal::service('access_manager');
  1153. if ($access_manager->checkNamedRoute('user.admin_permissions', array(), \Drupal::currentUser())) {
  1154. /** @var \Drupal\Core\Url $url */
  1155. $url = new Url('user.admin_permissions');
  1156. $url->setOption('fragment', 'module-' . $module);
  1157. $admin_tasks["user.admin_permissions.$module"] = array(
  1158. 'title' => t('Configure @module permissions', array('@module' => $info['name'])),
  1159. 'description' => '',
  1160. 'url' => $url,
  1161. );
  1162. }
  1163. }
  1164. return $admin_tasks;
  1165. }
  1166. /**
  1167. * Implements hook_cron().
  1168. *
  1169. * Remove older rows from flood, batch cache and expirable keyvalue tables.
  1170. */
  1171. function system_cron() {
  1172. // Clean up the flood.
  1173. \Drupal::flood()->garbageCollection();
  1174. foreach (Cache::getBins() as $cache_backend) {
  1175. $cache_backend->garbageCollection();
  1176. }
  1177. // Clean up the expirable key value database store.
  1178. if (\Drupal::service('keyvalue.expirable.database') instanceof KeyValueDatabaseExpirableFactory) {
  1179. \Drupal::service('keyvalue.expirable.database')->garbageCollection();
  1180. }
  1181. // Clean up any garbage in the queue service.
  1182. $queue_worker_manager = \Drupal::service('plugin.manager.queue_worker');
  1183. $queue_factory = \Drupal::service('queue');
  1184. foreach (array_keys($queue_worker_manager->getDefinitions()) as $queue_name) {
  1185. $queue = $queue_factory->get($queue_name);
  1186. if ($queue instanceof QueueGarbageCollectionInterface) {
  1187. $queue->garbageCollection();
  1188. }
  1189. }
  1190. // Clean up PHP storage.
  1191. PhpStorageFactory::get('container')->garbageCollection();
  1192. PhpStorageFactory::get('service_container')->garbageCollection();
  1193. }
  1194. /**
  1195. * Implements hook_mail().
  1196. */
  1197. function system_mail($key, &$message, $params) {
  1198. $token_service = \Drupal::token();
  1199. $context = $params['context'];
  1200. $subject = PlainTextOutput::renderFromHtml($token_service->replace($context['subject'], $context));
  1201. $body = $token_service->replace($context['message'], $context);
  1202. $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
  1203. $message['body'][] = $body;
  1204. }
  1205. /**
  1206. * Generate an array of time zones and their local time&date.
  1207. *
  1208. * @param $blank
  1209. * If evaluates true, prepend an empty time zone option to the array.
  1210. */
  1211. function system_time_zones($blank = NULL) {
  1212. $zonelist = timezone_identifiers_list();
  1213. $zones = $blank ? array('' => t('- None selected -')) : array();
  1214. foreach ($zonelist as $zone) {
  1215. // Because many time zones exist in PHP only for backward compatibility
  1216. // reasons and should not be used, the list is filtered by a regular
  1217. // expression.
  1218. if (preg_match('!^((Africa|America|Antarctica|Arctic|Asia|Atlantic|Australia|Europe|Indian|Pacific)/|UTC$)!', $zone)) {
  1219. $zones[$zone] = t('@zone', array('@zone' => t(str_replace('_', ' ', $zone))));
  1220. }
  1221. }
  1222. // Sort the translated time zones alphabetically.
  1223. asort($zones);
  1224. return $zones;
  1225. }
  1226. /**
  1227. * Attempts to get a file using Guzzle HTTP client and to store it locally.
  1228. *
  1229. * @param string $url
  1230. * The URL of the file to grab.
  1231. * @param string $destination
  1232. * Stream wrapper URI specifying where the file should be placed. If a
  1233. * directory path is provided, the file is saved into that directory under
  1234. * its original name. If the path contains a filename as well, that one will
  1235. * be used instead.
  1236. * If this value is omitted, the site's default files scheme will be used,
  1237. * usually "public://".
  1238. * @param bool $managed
  1239. * If this is set to TRUE, the file API hooks will be invoked and the file is
  1240. * registered in the database.
  1241. * @param int $replace
  1242. * Replace behavior when the destination file already exists:
  1243. * - FILE_EXISTS_REPLACE: Replace the existing file.
  1244. * - FILE_EXISTS_RENAME: Append _{incrementing number} until the filename is
  1245. * unique.
  1246. * - FILE_EXISTS_ERROR: Do nothing and return FALSE.
  1247. *
  1248. * @return mixed
  1249. * One of these possibilities:
  1250. * - If it succeeds and $managed is FALSE, the location where the file was
  1251. * saved.
  1252. * - If it succeeds and $managed is TRUE, a \Drupal\file\FileInterface
  1253. * object which describes the file.
  1254. * - If it fails, FALSE.
  1255. */
  1256. function system_retrieve_file($url, $destination = NULL, $managed = FALSE, $replace = FILE_EXISTS_RENAME) {
  1257. $parsed_url = parse_url($url);
  1258. if (!isset($destination)) {
  1259. $path = file_build_uri(drupal_basename($parsed_url['path']));
  1260. }
  1261. else {
  1262. if (is_dir(drupal_realpath($destination))) {
  1263. // Prevent URIs with triple slashes when glueing parts together.
  1264. $path = str_replace('///', '//', "$destination/") . drupal_basename($parsed_url['path']);
  1265. }
  1266. else {
  1267. $path = $destination;
  1268. }
  1269. }
  1270. try {
  1271. $data = (string) \Drupal::httpClient()
  1272. ->get($url)
  1273. ->getBody();
  1274. $local = $managed ? file_save_data($data, $path, $replace) : file_unmanaged_save_data($data, $path, $replace);
  1275. }
  1276. catch (RequestException $exception) {
  1277. drupal_set_message(t('Failed to fetch file due to error "%error"', array('%error' => $exception->getMessage())), 'error');
  1278. return FALSE;
  1279. }
  1280. if (!$local) {
  1281. drupal_set_message(t('@remote could not be saved to @path.', array('@remote' => $url, '@path' => $path)), 'error');
  1282. }
  1283. return $local;
  1284. }
  1285. /**
  1286. * Implements hook_entity_type_build().
  1287. */
  1288. function system_entity_type_build(array &$entity_types) {
  1289. /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
  1290. $entity_types['date_format']
  1291. ->setFormClass('add', 'Drupal\system\Form\DateFormatAddForm')
  1292. ->setFormClass('edit', 'Drupal\system\Form\DateFormatEditForm')
  1293. ->setFormClass('delete', 'Drupal\system\Form\DateFormatDeleteForm')
  1294. ->setListBuilderClass('Drupal\system\DateFormatListBuilder')
  1295. ->setLinkTemplate('edit-form', '/admin/config/regional/date-time/formats/manage/{date_format}')
  1296. ->setLinkTemplate('delete-form', '/admin/config/regional/date-time/formats/manage/{date_format}/delete')
  1297. ->setLinkTemplate('collection', '/admin/config/regional/date-time/formats');
  1298. }
  1299. /**
  1300. * Implements hook_block_view_BASE_BLOCK_ID_alter().
  1301. */
  1302. function system_block_view_system_main_block_alter(array &$build, BlockPluginInterface $block) {
  1303. // Contextual links on the system_main block would basically duplicate the
  1304. // tabs/local tasks, so reduce the clutter.
  1305. unset($build['#contextual_links']);
  1306. }
  1307. /**
  1308. * Implements hook_path_update().
  1309. */
  1310. function system_path_update($path) {
  1311. $alias_manager = \Drupal::service('path.alias_manager');
  1312. $alias_manager->cacheClear($path['source']);
  1313. $alias_manager->cacheClear($path['original']['source']);
  1314. }
  1315. /**
  1316. * Implements hook_path_insert().
  1317. */
  1318. function system_path_insert($path) {
  1319. \Drupal::service('path.alias_manager')->cacheClear($path['source']);
  1320. }
  1321. /**
  1322. * Implements hook_path_delete().
  1323. */
  1324. function system_path_delete($path) {
  1325. \Drupal::service('path.alias_manager')->cacheClear($path['source']);
  1326. }
  1327. /**
  1328. * Implements hook_query_TAG_alter() for entity reference selection handlers.
  1329. */
  1330. function system_query_entity_reference_alter(AlterableInterface $query) {
  1331. $handler = $query->getMetadata('entity_reference_selection_handler');
  1332. $handler->entityQueryAlter($query);
  1333. }

Functions

Namesort descending Description
system_admin_compact_mode Determines whether the current user is in compact mode.
system_authorized_batch_process Use authorize.php to run batch_process().
system_authorized_batch_processing_url Returns the URL for the authorize.php script when it is processing a batch.
system_authorized_get_url Return the URL for the authorize.php script.
system_authorized_init Setup a given callback to run via authorize.php with elevated privileges.
system_authorized_run Setup and invoke an operation using authorize.php.
system_block_view_system_main_block_alter Implements hook_block_view_BASE_BLOCK_ID_alter().
system_check_directory Checks the existence of the directory specified in $form_element.
system_cron Implements hook_cron().
system_default_region Gets the name of the default region for a given theme.
system_entity_type_build Implements hook_entity_type_build().
system_filetransfer_info Implements hook_filetransfer_info().
system_form_alter Implements hook_form_alter().
system_form_user_form_alter Implements hook_form_FORM_ID_alter() for \Drupal\user\AccountForm.
system_form_user_register_form_alter Implements hook_form_FORM_ID_alter() for \Drupal\user\RegisterForm.
system_get_info Returns an array of information about enabled modules or themes.
system_get_module_admin_tasks Generate a list of tasks offered by a specified module.
system_help Implements hook_help().
system_hook_info Implements hook_hook_info().
system_js_settings_alter Implements hook_js_settings_alter().
system_js_settings_build Implements hook_js_settings_build().
system_mail Implements hook_mail().
system_page_attachments Implements hook_page_attachments().
system_path_delete Implements hook_path_delete().
system_path_insert Implements hook_path_insert().
system_path_update Implements hook_path_update().
system_preprocess_block Implements hook_preprocess_HOOK() for block templates.
system_query_entity_reference_alter Implements hook_query_TAG_alter() for entity reference selection handlers.
system_rebuild_module_data Rebuild, save, and return data about all currently available modules.
system_region_list Get a list of available regions from a specified theme.
system_retrieve_file Attempts to get a file using Guzzle HTTP client and to store it locally.
system_sort_modules_by_info_name Array sorting callback; sorts modules by their name.
system_sort_themes Sorts themes by their names, with the default theme listed first.
system_system_info_alter Implements hook_system_info_alter().
system_theme Implements hook_theme().
system_theme_suggestions_field Implements hook_theme_suggestions_HOOK().
system_theme_suggestions_html Implements hook_theme_suggestions_HOOK().
system_theme_suggestions_maintenance_page Implements hook_theme_suggestions_HOOK().
system_theme_suggestions_page Implements hook_theme_suggestions_HOOK().
system_theme_suggestions_region Implements hook_theme_suggestions_HOOK().
system_time_zones Generate an array of time zones and their local time&date.
system_updater_info Implements hook_updater_info().
system_user_login Implements hook_user_login().
system_user_presave Implements hook_ENTITY_TYPE_presave() for user entities.
system_user_timezone Add the time zone field to the user edit and register forms.
template_preprocess_entity_add_list Prepares variables for the list of available bundles.
_system_rebuild_module_data Helper function to scan and collect module .info.yml data.
_system_rebuild_module_data_ensure_required Ensures that dependencies of required modules are also required.

Constants

Namesort descending Description
DRUPAL_DISABLED Disabled option on forms and settings
DRUPAL_OPTIONAL Optional option on forms and settings
DRUPAL_REQUIRED Required option on forms and settings
DRUPAL_USER_TIMEZONE_DEFAULT New users will be set to the default time zone at registration.
DRUPAL_USER_TIMEZONE_EMPTY New users will get an empty time zone at registration.
DRUPAL_USER_TIMEZONE_SELECT New users will select their own timezone at registration.
REGIONS_ALL Return all regions.
REGIONS_VISIBLE Return only visible regions.