system.module 58.9 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436
<?php

/**
 * @file
 * Configuration system that lets administrators modify the workings of the site.
 */

use Drupal\Component\Render\PlainTextOutput;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Asset\AttachedAssetsInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\KeyValueStore\KeyValueDatabaseExpirableFactory;
use Drupal\Core\PageCache\RequestPolicyInterface;
use Drupal\Core\PhpStorage\PhpStorageFactory;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\Core\Extension\ModuleHandler;
use Drupal\Core\Url;
use Drupal\Core\Block\BlockPluginInterface;
use Drupal\user\UserInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use GuzzleHttp\Exception\RequestException;

/**
 * New users will be set to the default time zone at registration.
 */
const DRUPAL_USER_TIMEZONE_DEFAULT = 0;

/**
 * New users will get an empty time zone at registration.
 */
const DRUPAL_USER_TIMEZONE_EMPTY = 1;

/**
 * New users will select their own timezone at registration.
 */
const DRUPAL_USER_TIMEZONE_SELECT = 2;

/**
 * Disabled option on forms and settings
 */
const DRUPAL_DISABLED = 0;

/**
 * Optional option on forms and settings
 */
const DRUPAL_OPTIONAL = 1;

/**
 * Required option on forms and settings
 */
const DRUPAL_REQUIRED = 2;

/**
 * Return only visible regions.
 *
 * @see system_region_list()
 */
const REGIONS_VISIBLE = 'visible';

/**
 * Return all regions.
 *
 * @see system_region_list()
 */
const REGIONS_ALL = 'all';

/**
 * Implements hook_help().
 */
function system_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'help.page.system':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $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>';
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . t('Managing modules') . '</dt>';
      $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>';
      $output .= '<dt>' . t('Managing themes') . '</dt>';
      $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>';
      $output .= '<dt>' . t('Disabling drag-and-drop functionality') . '</dt>';
      $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>';
      $output .= '<dt>' . t('Configuring basic site settings') . '</dt>';
      $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 basic <a href=":site-info">Site information</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>';
      $output .= '<dt>' . t('Checking site status') . '</dt>';
      $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>';
      $output .= '<dt>' . t('Using maintenance mode') . '</dt>';
      $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>';
      $output .= '<dt>' . t('Configuring for performance') . '</dt>';
      $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>';
      $output .= '<dt>' . t('Configuring cron') . '</dt>';
      $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>';
      $output .= '<dt>' . t('Configuring the file system') . '</dt>';
      $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>';
      $output .= '<dt>' . t('Configuring the image toolkit') . '</dt>';
      $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>';
      $output .= '</dl>';
      return $output;

    case 'system.admin_index':
      return '<p>' . t('This page shows you all available administration tasks for each module.') . '</p>';

    case 'system.themes_page':
      $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>';
      if (\Drupal::moduleHandler()->moduleExists('block')) {
        $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>';
      }
      return $output;

    case 'system.theme_settings_theme':
      $theme_list = \Drupal::service('theme_handler')->listInfo();
      $theme = $theme_list[$route_match->getParameter('theme')];
      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>';

    case 'system.theme_settings':
      return '<p>' . t('These options control the default display settings for your entire site, across all themes. Unless they have been overridden by a specific theme, these settings will be used.') . '</p>';

    case 'system.modules_list':
      $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>';
      if (!\Drupal::moduleHandler()->moduleExists('update')) {
        $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>';
      }
      return $output;

    case 'system.modules_uninstall':
      return '<p>' . t('The uninstall process removes all data related to a module.') . '</p>';

    case 'entity.block.edit_form':
      if (($block = $route_match->getParameter('block')) && $block->getPluginId() == 'system_powered_by_block') {
        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>';
      }
      break;

    case 'block.admin_add':
      if ($route_match->getParameter('plugin_id') == 'system_powered_by_block') {
        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>';
      }
      break;

    case 'system.site_maintenance_mode':
      if (\Drupal::currentUser()->id() == 1) {
        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>';
      }
      break;

    case 'system.status':
      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>';
  }
}

/**
 * Implements hook_theme().
 */
function system_theme() {
  return array_merge(drupal_common_theme(), array(
    // Normally theme suggestion templates are only picked up when they are in
    // themes. We explicitly define theme suggestions here so that the block
    // templates in core/modules/system/templates are picked up.
    'block__system_branding_block' => array(
      'render element' => 'elements',
      'base hook' => 'block',
    ),
    'block__system_messages_block' => array(
      'base hook' => 'block',
    ),
    'block__system_menu_block' => array(
      'render element' => 'elements',
      'base hook' => 'block',
    ),
    'system_themes_page' => array(
      'variables' => array(
        'theme_groups' => array(),
        'theme_group_titles' => array(),
      ),
      'file' => 'system.admin.inc',
    ),
    'system_config_form' => array(
      'render element' => 'form',
    ),
    'confirm_form' => array(
      'render element' => 'form',
    ),
    'system_modules_details' => array(
      'render element' => 'form',
      'file' => 'system.admin.inc',
    ),
    'system_modules_uninstall' => array(
      'render element' => 'form',
      'file' => 'system.admin.inc',
    ),
    'status_report' => array(
      'variables' => array('requirements' => NULL),
      'file' => 'system.admin.inc',
    ),
    'admin_page' => array(
      'variables' => array('blocks' => NULL),
      'file' => 'system.admin.inc',
    ),
    'admin_block' => array(
      'variables' => array('block' => NULL),
      'file' => 'system.admin.inc',
    ),
    'admin_block_content' => array(
      'variables' => array('content' => NULL),
      'file' => 'system.admin.inc',
    ),
    'system_admin_index' => array(
      'variables' => array('menu_items' => NULL),
      'file' => 'system.admin.inc',
    ),
  ));
}

/**
 * Implements hook_hook_info().
 */
function system_hook_info() {
  $hooks['token_info'] = array(
    'group' => 'tokens',
  );
  $hooks['token_info_alter'] = array(
    'group' => 'tokens',
  );
  $hooks['tokens'] = array(
    'group' => 'tokens',
  );
  $hooks['tokens_alter'] = array(
    'group' => 'tokens',
  );

  return $hooks;
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function system_theme_suggestions_html(array $variables) {
  if (\Drupal::service('path.matcher')->isFrontPage()) {
    $path_args = [''];
  }
  else {
    $path_args = explode('/', ltrim(\Drupal::service('path.current')->getPath(), '/'));
  }
  return theme_get_suggestions($path_args, 'html');
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function system_theme_suggestions_page(array $variables) {
  if (\Drupal::service('path.matcher')->isFrontPage()) {
    $path_args = [''];
  }
  else {
    $path_args = explode('/', Url::fromRoute('<current>')->getInternalPath());
  }
  return theme_get_suggestions($path_args, 'page');
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function system_theme_suggestions_maintenance_page(array $variables) {
  $suggestions = array();

  // Dead databases will show error messages so supplying this template will
  // allow themers to override the page and the content completely.
  $offline = defined('MAINTENANCE_MODE');
  try {
    \Drupal::service('path.matcher')->isFrontPage();
  }
  catch (Exception $e) {
    // The database is not yet available.
    $offline = TRUE;
  }
  if ($offline) {
    $suggestions[] = 'maintenance_page__offline';
  }

  return $suggestions;
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function system_theme_suggestions_region(array $variables) {
  $suggestions = array();
  if (!empty($variables['elements']['#region'])) {
    $suggestions[] = 'region__' . $variables['elements']['#region'];
  }
  return $suggestions;
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function system_theme_suggestions_field(array $variables) {
  $suggestions = array();
  $element = $variables['element'];

  $suggestions[] = 'field__' . $element['#field_type'];
  $suggestions[] = 'field__' . $element['#field_name'];
  $suggestions[] = 'field__' . $element['#entity_type'] . '__' . $element['#bundle'];
  $suggestions[] = 'field__' . $element['#entity_type'] . '__' . $element['#field_name'];
  $suggestions[] = 'field__' . $element['#entity_type'] . '__' . $element['#field_name'] . '__' . $element['#bundle'];

  return $suggestions;
}

/**
 * @defgroup authorize Authorized operations
 * @{
 * Functions to run operations with elevated privileges via authorize.php.
 *
 * Because of the Update manager functionality included in Drupal core, there
 * is a mechanism for running operations with elevated file system privileges,
 * the top-level authorize.php script. This script runs at a reduced Drupal
 * bootstrap level so that it is not reliant on the entire site being
 * functional. The operations use a FileTransfer class to manipulate code
 * installed on the system as the user that owns the files, not the user that
 * the httpd is running as.
 *
 * The first setup is to define a callback function that should be authorized
 * to run with the elevated privileges. This callback should take a
 * FileTransfer as its first argument, although you can define an array of
 * other arguments it should be invoked with. The callback should be placed in
 * a separate .inc file that will be included by authorize.php.
 *
 * To run the operation, certain data must be saved into the SESSION, and then
 * the flow of control should be redirected to the authorize.php script. There
 * are two ways to do this, either to call system_authorized_run() directly,
 * or to call system_authorized_init() and then redirect to authorize.php,
 * using the URL from system_authorized_get_url(). Redirecting yourself is
 * necessary when your authorized operation is being triggered by a form
 * submit handler, since calling redirecting in a submit handler is a bad
 * idea, and you should instead use $form_state->setRedirect().
 *
 * Once the SESSION is setup for the operation and the user is redirected to
 * authorize.php, they will be prompted for their connection credentials (core
 * provides FTP and SSH by default, although other connection classes can be
 * added via contributed modules). With valid credentials, authorize.php will
 * instantiate the appropriate FileTransfer object, and then invoke the
 * desired operation passing in that object. The authorize.php script can act
 * as a Batch API processing page, if the operation requires a batch.
 *
 * @see authorize.php
 * @see \Drupal\Core\FileTransfer\FileTransfer
 * @see hook_filetransfer_info()
 */

/**
 * Setup a given callback to run via authorize.php with elevated privileges.
 *
 * To use authorize.php, certain variables must be stashed into $_SESSION. This
 * function sets up all the necessary $_SESSION variables. The calling function
 * should then redirect to authorize.php, using the full path returned by
 * system_authorized_get_url(). That initiates the workflow that will eventually
 * lead to the callback being invoked. The callback will be invoked at a low
 * bootstrap level, without all modules being invoked, so it needs to be careful
 * not to assume any code exists. Example (system_authorized_run()):
 * @code
 *   system_authorized_init($callback, $file, $arguments, $page_title);
 *   return new RedirectResponse(system_authorized_get_url()->toString());
 * @endcode
 * Example (update_manager_install_form_submit()):
 * @code
 *  system_authorized_init('update_authorize_run_install',
 *    drupal_get_path('module', 'update') . '/update.authorize.inc',
 *    $arguments, t('Update manager'));
 *  $form_state->setRedirectUrl(system_authorized_get_url());
 * @endcode
 *
 * @param $callback
 *   The name of the function to invoke once the user authorizes the operation.
 * @param $file
 *   The full path to the file where the callback function is implemented.
 * @param $arguments
 *   Optional array of arguments to pass into the callback when it is invoked.
 *   Note that the first argument to the callback is always the FileTransfer
 *   object created by authorize.php when the user authorizes the operation.
 * @param $page_title
 *   Optional string to use as the page title once redirected to authorize.php.
 * @return
 *   Nothing, this function just initializes variables in the user's session.
 */
function system_authorized_init($callback, $file, $arguments = array(), $page_title = NULL) {
  // First, figure out what file transfer backends the site supports, and put
  // all of those in the SESSION so that authorize.php has access to all of
  // them via the class autoloader, even without a full bootstrap.
  $_SESSION['authorize_filetransfer_info'] = drupal_get_filetransfer_info();

  // Now, define the callback to invoke.
  $_SESSION['authorize_operation'] = array(
    'callback' => $callback,
    'file' => $file,
    'arguments' => $arguments,
  );

  if (isset($page_title)) {
    $_SESSION['authorize_page_title'] = $page_title;
  }
}

/**
 * Return the URL for the authorize.php script.
 *
 * @param array $options
 *   Optional array of options to pass to url().
 * @return \Drupal\Core\Url
 *   The full URL to authorize.php, using HTTPS if available.
 *
 * @see system_authorized_init()
 */
function system_authorized_get_url(array $options = array()) {
  // core/authorize.php is an unrouted URL, so using the base: scheme is
  // the correct usage for this case.
  $url = Url::fromUri('base:core/authorize.php');
  $url_options = $url->getOptions();
  $url->setOptions($options + $url_options);
  return $url;
}

/**
 * Returns the URL for the authorize.php script when it is processing a batch.
 *
 * @param array $options
 *   Optional array of options to pass to url().
 *
 * @return \Drupal\Core\Url
 */
function system_authorized_batch_processing_url(array $options = array()) {
  $options['query'] = array('batch' => '1');
  return system_authorized_get_url($options);
}

/**
 * Setup and invoke an operation using authorize.php.
 *
 * @see system_authorized_init()
 */
function system_authorized_run($callback, $file, $arguments = array(), $page_title = NULL) {
  system_authorized_init($callback, $file, $arguments, $page_title);
  return new RedirectResponse(system_authorized_get_url()->toString());
}

/**
 * Use authorize.php to run batch_process().
 *
 * @see batch_process()
 */
function system_authorized_batch_process() {
  $finish_url = system_authorized_get_url();
  $process_url = system_authorized_batch_processing_url();
  return batch_process($finish_url->setAbsolute()->toString(), $process_url);
}

/**
 * @} End of "defgroup authorize".
 */

/**
 * Implements hook_updater_info().
 */
function system_updater_info() {
  return array(
    'module' => array(
      'class' => 'Drupal\Core\Updater\Module',
      'name' => t('Update modules'),
      'weight' => 0,
    ),
    'theme' => array(
      'class' => 'Drupal\Core\Updater\Theme',
      'name' => t('Update themes'),
      'weight' => 0,
    ),
  );
}

/**
 * Implements hook_filetransfer_info().
 */
function system_filetransfer_info() {
  $backends = array();

  // This is the default, will be available on most systems.
  if (function_exists('ftp_connect')) {
    $backends['ftp'] = array(
      'title' => t('FTP'),
      'class' => 'Drupal\Core\FileTransfer\FTP',
      'weight' => 0,
    );
  }

  // SSH2 lib connection is only available if the proper PHP extension is
  // installed.
  if (function_exists('ssh2_connect')) {
    $backends['ssh'] = array(
      'title' => t('SSH'),
      'class' => 'Drupal\Core\FileTransfer\SSH',
      'weight' => 20,
    );
  }
  return $backends;
}

/**
 * Implements hook_page_attachments().
 *
 * @see template_preprocess_maintenance_page()
 * @see \Drupal\Core\EventSubscriber\ActiveLinkResponseFilter
 */
function system_page_attachments(array &$page) {
  // Ensure the same CSS is loaded in template_preprocess_maintenance_page().
  $page['#attached']['library'][] = 'system/base';
  if (\Drupal::service('router.admin_context')->isAdminRoute()) {
    $page['#attached']['library'][] = 'system/admin';
  }

  // Attach libraries used by this theme.
  $active_theme = \Drupal::theme()->getActiveTheme();
  foreach ($active_theme->getLibraries() as $library) {
    $page['#attached']['library'][] = $library;
  }

  // Attach favicon.
  if (theme_get_setting('features.favicon')) {
    $favicon = theme_get_setting('favicon.url');
    $type = theme_get_setting('favicon.mimetype');
    $page['#attached']['html_head_link'][][] = array(
      'rel' => 'shortcut icon',
      'href' => UrlHelper::stripDangerousProtocols($favicon),
      'type' => $type,
    );
  }

  // Get the major Drupal version.
  list($version, ) = explode('.', \Drupal::VERSION);

  // Attach default meta tags.
  $meta_default = array(
    // Make sure the Content-Type comes first because the IE browser may be
    // vulnerable to XSS via encoding attacks from any content that comes
    // before this META tag, such as a TITLE tag.
    'system_meta_content_type' => array(
      '#tag' => 'meta',
      '#attributes' => array(
        'charset' => 'utf-8',
      ),
      // Security: This always has to be output first.
      '#weight' => -1000,
    ),
    // Show Drupal and the major version number in the META GENERATOR tag.
    'system_meta_generator' => array(
      '#type' => 'html_tag',
      '#tag' => 'meta',
      '#attributes' => array(
        'name' => 'Generator',
        'content' => 'Drupal ' . $version . ' (https://www.drupal.org)',
      ),
    ),
    // Attach default mobile meta tags for responsive design.
    'MobileOptimized' => array(
      '#tag' => 'meta',
      '#attributes' => array(
        'name' => 'MobileOptimized',
        'content' => 'width',
      ),
    ),
    'HandheldFriendly' => array(
      '#tag' => 'meta',
      '#attributes' => array(
        'name' => 'HandheldFriendly',
        'content' => 'true',
      ),
    ),
    'viewport' => array(
      '#tag' => 'meta',
      '#attributes' => array(
        'name' => 'viewport',
        'content' => 'width=device-width, initial-scale=1.0',
      ),
    ),
  );
  foreach ($meta_default as $key => $value) {
    $page['#attached']['html_head'][] = [$value, $key];
  }

  // Handle setting the "active" class on links by:
  // - loading the active-link library if the current user is authenticated;
  // - applying a response filter if the current user is anonymous.
  // @see l()
  // @see \Drupal\Core\Utility\LinkGenerator::generate()
  // @see template_preprocess_links()
  // @see \Drupal\Core\EventSubscriber\ActiveLinkResponseFilter
  if (\Drupal::currentUser()->isAuthenticated()) {
    $page['#attached']['library'][] = 'core/drupal.active-link';
  }
}

/**
 * Implements hook_js_settings_build().
 *
 * Sets values for the core/drupal.ajax library, which just depends on the
 * active theme but no other request-dependent values.
 */
function system_js_settings_build(&$settings, AttachedAssetsInterface $assets) {
  // Generate the values for the core/drupal.ajax library.
  // We need to send ajaxPageState settings for core/drupal.ajax if:
  // - ajaxPageState is being loaded in this Response, in which case it will
  //   already exist at $settings['ajaxPageState'] (because the core/drupal.ajax
  //   library definition specifies a placeholder 'ajaxPageState' setting).
  // - core/drupal.ajax already has been loaded and hence this is an AJAX
  //   Response in which we must send the list of extra asset libraries that are
  //   being added in this AJAX Response.
  /** @var \Drupal\Core\Asset\LibraryDependencyResolver $library_dependency_resolver */
  $library_dependency_resolver = \Drupal::service('library.dependency_resolver');
  if (isset($settings['ajaxPageState']) || in_array('core/drupal.ajax', $library_dependency_resolver->getLibrariesWithDependencies($assets->getAlreadyLoadedLibraries()))) {
    // Provide the page with information about the theme that's used, so that
    // a later AJAX request can be rendered using the same theme.
    // @see \Drupal\Core\Theme\AjaxBasePageNegotiator
    $theme_key = \Drupal::theme()->getActiveTheme()->getName();
    $settings['ajaxPageState']['theme'] = $theme_key;

    // Provide the page with information about the individual asset libraries
    // used, information not otherwise available when aggregation is enabled.
    $minimal_libraries = $library_dependency_resolver->getMinimalRepresentativeSubset(array_merge(
      $assets->getLibraries(),
      $assets->getAlreadyLoadedLibraries()
    ));
    sort($minimal_libraries);
    $settings['ajaxPageState']['libraries'] = implode(',', $minimal_libraries);
  }
}

/**
 * Implements hook_js_settings_alter().
 *
 * Sets values which depend on the current request, like core/drupalSettings
 * as well as theme_token ajax state.
 */
function system_js_settings_alter(&$settings, AttachedAssetsInterface $assets) {
  $request = \Drupal::request();
  $current_query = $request->query->all();

  // Let output path processors set a prefix.
  /** @var \Drupal\Core\PathProcessor\OutboundPathProcessorInterface $path_processor */
  $path_processor = \Drupal::service('path_processor_manager');
  $options = ['prefix' => ''];
  $path_processor->processOutbound('/', $options);
  $pathPrefix = $options['prefix'];

  $current_path = \Drupal::routeMatch()->getRouteName() ? Url::fromRouteMatch(\Drupal::routeMatch())->getInternalPath() : '';
  $current_path_is_admin = \Drupal::service('router.admin_context')->isAdminRoute();
  $path_settings = [
    'baseUrl' => $request->getBaseUrl() . '/',
    'pathPrefix' => $pathPrefix,
    'currentPath' => $current_path,
    'currentPathIsAdmin' => $current_path_is_admin,
    'isFront' => \Drupal::service('path.matcher')->isFrontPage(),
    'currentLanguage' => \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId(),
  ];
  if (!empty($current_query)) {
    ksort($current_query);
    $path_settings['currentQuery'] = (object) $current_query;
  }

  // Only set core/drupalSettings values that haven't been set already.
  foreach ($path_settings as $key => $value) {
    if (!isset($settings['path'][$key])) {
      $settings['path'][$key] = $value;
    }
  }
  if (!isset($settings['pluralDelimiter'])) {
    $settings['pluralDelimiter'] = LOCALE_PLURAL_DELIMITER;
  }
  // Add the theme token to ajaxPageState, ensuring the database is available
  // before doing so.
  /** @var \Drupal\Core\Asset\LibraryDependencyResolver $library_dependency_resolver */
  $library_dependency_resolver = \Drupal::service('library.dependency_resolver');
  if (isset($settings['ajaxPageState']) || in_array('core/drupal.ajax', $library_dependency_resolver->getLibrariesWithDependencies($assets->getAlreadyLoadedLibraries()))) {
    if (!defined('MAINTENANCE_MODE')) {
      // The theme token is only validated when the theme requested is not the
      // default, so don't generate it unless necessary.
      // @see \Drupal\Core\Theme\AjaxBasePageNegotiator::determineActiveTheme()
      $active_theme_key = \Drupal::theme()->getActiveTheme()->getName();
      if ($active_theme_key !== \Drupal::service('theme_handler')->getDefault()) {
        $settings['ajaxPageState']['theme_token'] = \Drupal::csrfToken()
          ->get($active_theme_key);
      }
    }
  }
}

/**
 * Implements hook_form_alter().
 */
function system_form_alter(&$form, FormStateInterface $form_state) {
  // If the page that's being built is cacheable, set the 'immutable' flag, to
  // ensure that when the form is used, a new form build ID is generated when
  // appropriate, to prevent information disclosure.

  // Note: This code just wants to know whether cache response headers are set,
  // not whether page_cache module will be active.
  // \Drupal\Core\EventSubscriber\FinishResponseSubscriber::onRespond will
  // send those headers, in case $request_policy->check($request) succeeds. In
  // that case we need to ensure that the immutable flag is sot, so future POST
  // request won't take over the form state of another user.
  /** @var \Drupal\Core\PageCache\RequestPolicyInterface $request_policy */
  $request_policy = \Drupal::service('page_cache_request_policy');
  $request = \Drupal::requestStack()->getCurrentRequest();
  $request_is_cacheable = $request_policy->check($request) === RequestPolicyInterface::ALLOW;
  if ($request_is_cacheable) {
    $form_state->addBuildInfo('immutable', TRUE);
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function system_form_user_form_alter(&$form, FormStateInterface $form_state) {
  if (\Drupal::config('system.date')->get('timezone.user.configurable')) {
    system_user_timezone($form, $form_state);
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function system_form_user_register_form_alter(&$form, FormStateInterface $form_state) {
  $config = \Drupal::config('system.date');
  if ($config->get('timezone.user.configurable') && $config->get('timezone.user.default') == DRUPAL_USER_TIMEZONE_SELECT) {
    system_user_timezone($form, $form_state);
  }
}

/**
 * Implements hook_ENTITY_TYPE_presave() for user entities.
 */
function system_user_presave(UserInterface $account) {
  $config = \Drupal::config('system.date');
  if ($config->get('timezone.user.configurable') && !$account->getTimeZone() && !$config->get('timezone.user.default')) {
    $account->timezone = $config->get('timezone.default');
  }
}

/**
 * Implements hook_user_login().
 */
function system_user_login(UserInterface $account) {
  $config = \Drupal::config('system.date');
  // If the user has a NULL time zone, notify them to set a time zone.
  if (!$account->getTimezone() && $config->get('timezone.user.configurable') && $config->get('timezone.user.warn')) {
    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')))));
  }
}

/**
 * Add the time zone field to the user edit and register forms.
 */
function system_user_timezone(&$form, FormStateInterface $form_state) {
  $user = \Drupal::currentUser();

  $account = $form_state->getFormObject()->getEntity();
  $form['timezone'] = array(
    '#type' => 'details',
    '#title' => t('Locale settings'),
    '#open' => TRUE,
    '#weight' => 6,
  );
  $form['timezone']['timezone'] = array(
    '#type' => 'select',
    '#title' => t('Time zone'),
    '#default_value' => $account->getTimezone() ? $account->getTimezone() : \Drupal::config('system.date')->get('timezone.default'),
    '#options' => system_time_zones($account->id() != $user->id()),
    '#description' => t('Select the desired local time and time zone. Dates and times throughout this site will be displayed using this time zone.'),
  );
  $user_input = $form_state->getUserInput();
  if (!$account->getTimezone() && $account->id() == $user->id() && empty($user_input['timezone'])) {
    $form['timezone']['#attached']['library'][] = 'core/drupal.timezone';
    $form['timezone']['timezone']['#attributes'] = array('class' => array('timezone-detect'));
  }
}

/**
 * Implements hook_preprocess_HOOK() for block templates.
 */
function system_preprocess_block(&$variables) {
  switch ($variables['base_plugin_id']) {
    case 'system_branding_block':
      $variables['site_logo'] = '';
      if ($variables['content']['site_logo']['#access'] && $variables['content']['site_logo']['#uri']) {
        $variables['site_logo'] = $variables['content']['site_logo']['#uri'];
      }
      $variables['site_name'] = '';
      if ($variables['content']['site_name']['#access'] && $variables['content']['site_name']['#markup']) {
        $variables['site_name'] = $variables['content']['site_name']['#markup'];
      }
      $variables['site_slogan'] = '';
      if ($variables['content']['site_slogan']['#access'] && $variables['content']['site_slogan']['#markup']) {
        $variables['site_slogan']['#markup'] = $variables['content']['site_slogan']['#markup'];
      }
      break;

    case 'system_powered_by_block':
      $variables['attributes']['role'] = 'complementary';
      break;
  }
}

/**
 * Checks the existence of the directory specified in $form_element.
 *
 * This function is called from the system_settings form to check all core
 * file directories (file_public_path, file_private_path, file_temporary_path).
 *
 * @param $form_element
 *   The form element containing the name of the directory to check.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The current state of the form.
 */
function system_check_directory($form_element, FormStateInterface $form_state) {
  $directory = $form_element['#value'];
  if (strlen($directory) == 0) {
    return $form_element;
  }

  $logger = \Drupal::logger('file system');
  if (!is_dir($directory) && !drupal_mkdir($directory, NULL, TRUE)) {
    // If the directory does not exists and cannot be created.
    $form_state->setErrorByName($form_element['#parents'][0], t('The directory %directory does not exist and could not be created.', array('%directory' => $directory)));
    $logger->error('The directory %directory does not exist and could not be created.', array('%directory' => $directory));
  }

  if (is_dir($directory) && !is_writable($directory) && !drupal_chmod($directory)) {
    // If the directory is not writable and cannot be made so.
    $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)));
    $logger->error('The directory %directory exists but is not writable and could not be made writable.', array('%directory' => $directory));
  }
  elseif (is_dir($directory)) {
    if ($form_element['#name'] == 'file_public_path') {
      // Create public .htaccess file.
      file_save_htaccess($directory, FALSE);
    }
    else {
      // Create private .htaccess file.
      file_save_htaccess($directory);
    }
  }

  return $form_element;
}

/**
 * Returns an array of information about enabled modules or themes.
 *
 * This function returns the contents of the .info.yml file for each installed
 * module or theme.
 *
 * @param $type
 *   Either 'module' or 'theme'.
 * @param $name
 *   (optional) The name of a module or theme whose information shall be
 *   returned. If omitted, all records for the provided $type will be returned.
 *   If $name does not exist in the provided $type or is not enabled, an empty
 *   array will be returned.
 *
 * @return
 *   An associative array of module or theme information keyed by name, or only
 *   information for $name, if given. If no records are available, an empty
 *   array is returned.
 *
 * @see system_rebuild_module_data()
 * @see \Drupal\Core\Extension\ThemeHandlerInterface::rebuildThemeData()
 */
function system_get_info($type, $name = NULL) {
  if ($type == 'module') {
    $info = &drupal_static(__FUNCTION__);
    if (!isset($info)) {
      if ($cache = \Drupal::cache()->get('system.module.info')) {
        $info = $cache->data;
      }
      else {
        $data = system_rebuild_module_data();
        foreach (\Drupal::moduleHandler()->getModuleList() as $module => $filename) {
          if (isset($data[$module])) {
            $info[$module] = $data[$module]->info;
          }
        }
        // Store the module information in cache. This cache is cleared by
        // calling system_rebuild_module_data(), for example, when listing
        // modules, (un)installing modules, importing configuration, updating
        // the site and when flushing all the caches.
        \Drupal::cache()->set('system.module.info', $info);
      }
    }
  }
  else {
    $info = array();
    $list = system_list($type);
    foreach ($list as $shortname => $item) {
      if (!empty($item->status)) {
        $info[$shortname] = $item->info;
      }
    }
  }
  if (isset($name)) {
    return isset($info[$name]) ? $info[$name] : array();
  }
  return $info;
}

/**
 * Helper function to scan and collect module .info.yml data.
 *
 * @return \Drupal\Core\Extension\Extension[]
 *   An associative array of module information.
 */
function _system_rebuild_module_data() {
  $listing = new ExtensionDiscovery(\Drupal::root());

  // Find installation profiles. This needs to happen before performing a
  // module scan as the module scan requires knowing what the active profile is.
  // @todo Remove as part of https://www.drupal.org/node/2186491.
  $profiles = $listing->scan('profile');
  $profile = drupal_get_profile();
  if ($profile && isset($profiles[$profile])) {
    // Prime the drupal_get_filename() static cache with the profile info file
    // location so we can use drupal_get_path() on the active profile during
    // the module scan.
    // @todo Remove as part of https://www.drupal.org/node/2186491.
    drupal_get_filename('profile', $profile, $profiles[$profile]->getPathname());
  }

  // Find modules.
  $modules = $listing->scan('module');
  // Include the installation profile in modules that are loaded.
  if ($profile) {
    $modules[$profile] = $profiles[$profile];
    // Installation profile hooks are always executed last.
    $modules[$profile]->weight = 1000;
  }

  // Set defaults for module info.
  $defaults = array(
    'dependencies' => array(),
    'description' => '',
    'package' => 'Other',
    'version' => NULL,
    'php' => DRUPAL_MINIMUM_PHP,
  );

  // Read info files for each module.
  foreach ($modules as $key => $module) {
    // Look for the info file.
    $module->info = \Drupal::service('info_parser')->parse($module->getPathname());

    // Add the info file modification time, so it becomes available for
    // contributed modules to use for ordering module lists.
    $module->info['mtime'] = $module->getMTime();

    // Merge in defaults and save.
    $modules[$key]->info = $module->info + $defaults;

    // Installation profiles are hidden by default, unless explicitly specified
    // otherwise in the .info.yml file.
    if ($key == $profile && !isset($modules[$key]->info['hidden'])) {
      $modules[$key]->info['hidden'] = TRUE;
    }

    // Invoke hook_system_info_alter() to give installed modules a chance to
    // modify the data in the .info.yml files if necessary.
    // @todo Remove $type argument, obsolete with $module->getType().
    $type = 'module';
    \Drupal::moduleHandler()->alter('system_info', $modules[$key]->info, $modules[$key], $type);
  }

  // It is possible that a module was marked as required by
  // hook_system_info_alter() and modules that it depends on are not required.
  foreach ($modules as $module) {
    _system_rebuild_module_data_ensure_required($module, $modules);
  }


  if ($profile && isset($modules[$profile])) {
    // The installation profile is required, if it's a valid module.
    $modules[$profile]->info['required'] = TRUE;
    // Add a default distribution name if the profile did not provide one.
    // @see install_profile_info()
    // @see drupal_install_profile_distribution_name()
    if (!isset($modules[$profile]->info['distribution']['name'])) {
      $modules[$profile]->info['distribution']['name'] = 'Drupal';
    }
  }

  return $modules;
}

/**
 * Ensures that dependencies of required modules are also required.
 *
 * @param \Drupal\Core\Extension\Extension $module
 *   The module info.
 * @param \Drupal\Core\Extension\Extension[] $modules
 *   The array of all module info.
 */
function _system_rebuild_module_data_ensure_required($module, &$modules) {
  if (!empty($module->info['required'])) {
    foreach ($module->info['dependencies'] as $dependency) {
      $dependency_name = ModuleHandler::parseDependency($dependency)['name'];
      if (!isset($modules[$dependency_name]->info['required'])) {
        $modules[$dependency_name]->info['required'] = TRUE;
        $modules[$dependency_name]->info['explanation'] = t('Dependency of required module @module', array('@module' => $module->info['name']));
        // Ensure any dependencies it has are required.
        _system_rebuild_module_data_ensure_required($modules[$dependency_name], $modules);
      }
    }
  }
}

/**
 * Rebuild, save, and return data about all currently available modules.
 *
 * @return \Drupal\Core\Extension\Extension[]
 *   Array of all available modules and their data.
 */
function system_rebuild_module_data() {
  $modules_cache = &drupal_static(__FUNCTION__);
  // Only rebuild once per request. $modules and $modules_cache cannot be
  // combined into one variable, because the $modules_cache variable is reset by
  // reference from system_list_reset() during the rebuild.
  if (!isset($modules_cache)) {
    $modules = _system_rebuild_module_data();
    $files = array();
    ksort($modules);
    // Add status, weight, and schema version.
    $installed_modules = \Drupal::config('core.extension')->get('module') ?: array();
    foreach ($modules as $name => $module) {
      $module->weight = isset($installed_modules[$name]) ? $installed_modules[$name] : 0;
      $module->status = (int) isset($installed_modules[$name]);
      $module->schema_version = SCHEMA_UNINSTALLED;
      $files[$name] = $module->getPathname();
    }
    $modules = \Drupal::moduleHandler()->buildModuleDependencies($modules);
    $modules_cache = $modules;

    // Store filenames to allow drupal_get_filename() to retrieve them without
    // having to rebuild or scan the filesystem.
    \Drupal::state()->set('system.module.files', $files);
    // Clear the module info cache.
    \Drupal::cache()->delete('system.module.info');
    drupal_static_reset('system_get_info');
  }
  return $modules_cache;
}

/**
 * Returns an array of default theme features.
 */
function _system_default_theme_features() {
  return array(
    'favicon',
    'node_user_picture',
    'comment_user_picture',
    'comment_user_verification',
  );
}

/**
 * Get a list of available regions from a specified theme.
 *
 * @param \Drupal\Core\Extension\Extension|string $theme
 *   A theme extension object, or the name of a theme.
 * @param $show
 *   Possible values: REGIONS_ALL or REGIONS_VISIBLE. Visible excludes hidden
 *   regions.
 * @return
 *   An array of regions in the form $region['name'] = 'description'.
 */
function system_region_list($theme, $show = REGIONS_ALL) {
  if (!$theme instanceof Extension) {
    $themes = \Drupal::service('theme_handler')->listInfo();
    if (!isset($themes[$theme])) {
      return array();
    }
    $theme = $themes[$theme];
  }
  $list = array();
  $info = $theme->info;
  // If requested, suppress hidden regions. See block_admin_display_form().
  foreach ($info['regions'] as $name => $label) {
    if ($show == REGIONS_ALL || !isset($info['regions_hidden']) || !in_array($name, $info['regions_hidden'])) {
      $list[$name] = t($label);
    }
  }

  return $list;
}

/**
 * Array sorting callback; sorts modules by their name.
 */
function system_sort_modules_by_info_name($a, $b) {
  return strcasecmp($a->info['name'], $b->info['name']);
}

/**
 * Sorts themes by their names, with the default theme listed first.
 *
 * Callback for uasort() within
 * \Drupal\system\Controller\SystemController::themesPage().
 *
 * @see system_sort_modules_by_info_name().
 */
function system_sort_themes($a, $b) {
  if ($a->is_default) {
    return -1;
  }
  if ($b->is_default) {
    return 1;
  }
  return strcasecmp($a->info['name'], $b->info['name']);
}

/**
 * Implements hook_system_info_alter().
 */
function system_system_info_alter(&$info, Extension $file, $type) {
  // Remove page-top and page-bottom from the blocks UI since they are reserved for
  // modules to populate from outside the blocks system.
  if ($type == 'theme') {
    $info['regions_hidden'][] = 'page_top';
    $info['regions_hidden'][] = 'page_bottom';
  }
}

/**
 * Gets the name of the default region for a given theme.
 *
 * @param $theme
 *   The name of a theme.
 * @return
 *   A string that is the region name.
 */
function system_default_region($theme) {
  $regions = array_keys(system_region_list($theme, REGIONS_VISIBLE));
  return isset($regions[0]) ? $regions[0] : '';
}

/**
 * Determines whether the current user is in compact mode.
 *
 * Compact mode shows certain administration pages with less description text,
 * such as the configuration page and the permissions page.
 *
 * Whether the user is in compact mode is determined by a cookie, which is set
 * for the user by \Drupal\system\Controller\SystemController::compactPage().
 *
 * If the user does not have the cookie, the default value is given by the
 * system variable 'admin_compact_mode', which itself defaults to FALSE. This
 * does not have a user interface to set it: it is a hidden variable which can
 * be set in the settings.php file.
 *
 * @return bool
 *   TRUE when in compact mode, FALSE when in expanded mode.
 */
function system_admin_compact_mode() {
  // PHP converts dots into underscores in cookie names to avoid problems with
  // its parser, so we use a converted cookie name.
  return \Drupal::request()->cookies->get('Drupal_visitor_admin_compact_mode', \Drupal::config('system.site')->get('admin_compact_mode'));
}

/**
 * Generate a list of tasks offered by a specified module.
 *
 * @param string $module
 *   Module name.
 * @param array $info
 *   The module's information, as provided by system_get_info().
 *
 * @return array
 *   An array of task links.
 */
function system_get_module_admin_tasks($module, array $info) {
  $tree = &drupal_static(__FUNCTION__);

  $menu_tree = \Drupal::menuTree();

  if (!isset($tree)) {
    $parameters = new MenuTreeParameters();
    $parameters->setRoot('system.admin')->excludeRoot()->onlyEnabledLinks();
    $tree = $menu_tree->load('system.admin', $parameters);
    $manipulators = array(
      array('callable' => 'menu.default_tree_manipulators:checkAccess'),
      array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
      array('callable' => 'menu.default_tree_manipulators:flatten'),
    );
    $tree = $menu_tree->transform($tree, $manipulators);
  }

  $admin_tasks = array();
  foreach ($tree as $element) {
    if (!$element->access->isAllowed()) {
      // @todo Bubble cacheability metadata of both accessible and inaccessible
      //   links. Currently made impossible by the way admin tasks are rendered.
      continue;
    }

    $link = $element->link;
    if ($link->getProvider() != $module) {
      continue;
    }
    $admin_tasks[] = array(
      'title' => $link->getTitle(),
      'description' => $link->getDescription(),
      'url' => $link->getUrlObject(),
    );
  }

  // Append link for permissions.
  /** @var \Drupal\user\PermissionHandlerInterface $permission_handler */
  $permission_handler = \Drupal::service('user.permissions');

  if ($permission_handler->moduleProvidesPermissions($module)) {
    /** @var \Drupal\Core\Access\AccessManagerInterface $access_manager */
    $access_manager = \Drupal::service('access_manager');
    if ($access_manager->checkNamedRoute('user.admin_permissions', array(), \Drupal::currentUser())) {
      /** @var \Drupal\Core\Url $url */
      $url = new \Drupal\Core\Url('user.admin_permissions');
      $url->setOption('fragment', 'module-' . $module);
      $admin_tasks["user.admin_permissions.$module"] = array(
        'title' => t('Configure @module permissions', array('@module' => $info['name'])),
        'description' => '',
        'url' => $url,
      );
    }
  }

  return $admin_tasks;
}

/**
 * Implements hook_cron().
 *
 * Remove older rows from flood, batch cache and expirable keyvalue tables.
 */
function system_cron() {
  // Clean up the flood.
  \Drupal::flood()->garbageCollection();

  foreach (Cache::getBins() as $cache_backend) {
    $cache_backend->garbageCollection();
  }

  // Clean up the expirable key value database store.
  if (\Drupal::service('keyvalue.expirable.database') instanceof KeyValueDatabaseExpirableFactory) {
    \Drupal::service('keyvalue.expirable.database')->garbageCollection();
  }

  // Clean up the queue for failed batches.
  db_delete('queue')
    ->condition('created', REQUEST_TIME - 864000, '<')
    ->condition('name', 'drupal_batch:%', 'LIKE')
    ->execute();

  // Reset expired items in the default queue implementation table. If that's
  // not used, this will simply be a no-op.
  db_update('queue')
    ->fields(array(
      'expire' => 0,
    ))
    ->condition('expire', 0, '<>')
    ->condition('expire', REQUEST_TIME, '<')
    ->execute();

  // Clean up PHP storage.
  PhpStorageFactory::get('container')->garbageCollection();
  PhpStorageFactory::get('service_container')->garbageCollection();
}

/**
 * Implements hook_mail().
 */
function system_mail($key, &$message, $params) {
  $token_service = \Drupal::token();

  $context = $params['context'];

  $subject = PlainTextOutput::renderFromHtml($token_service->replace($context['subject'], $context));
  $body = $token_service->replace($context['message'], $context);

  $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
  $message['body'][] = $body;
}

/**
 * Generate an array of time zones and their local time&date.
 *
 * @param $blank
 *   If evaluates true, prepend an empty time zone option to the array.
 */
function system_time_zones($blank = NULL) {
  $zonelist = timezone_identifiers_list();
  $zones = $blank ? array('' => t('- None selected -')) : array();
  foreach ($zonelist as $zone) {
    // Because many time zones exist in PHP only for backward compatibility
    // reasons and should not be used, the list is filtered by a regular
    // expression.
    if (preg_match('!^((Africa|America|Antarctica|Arctic|Asia|Atlantic|Australia|Europe|Indian|Pacific)/|UTC$)!', $zone)) {
      $zones[$zone] = t('@zone', array('@zone' => t(str_replace('_', ' ', $zone))));
    }
  }
  // Sort the translated time zones alphabetically.
  asort($zones);
  return $zones;
}

/**
 * Attempts to get a file using Guzzle HTTP client and to store it locally.
 *
 * @param string $url
 *   The URL of the file to grab.
 * @param string $destination
 *   Stream wrapper URI specifying where the file should be placed. If a
 *   directory path is provided, the file is saved into that directory under
 *   its original name. If the path contains a filename as well, that one will
 *   be used instead.
 *   If this value is omitted, the site's default files scheme will be used,
 *   usually "public://".
 * @param bool $managed
 *   If this is set to TRUE, the file API hooks will be invoked and the file is
 *   registered in the database.
 * @param int $replace
 *   Replace behavior when the destination file already exists:
 *   - FILE_EXISTS_REPLACE: Replace the existing file.
 *   - FILE_EXISTS_RENAME: Append _{incrementing number} until the filename is
 *     unique.
 *   - FILE_EXISTS_ERROR: Do nothing and return FALSE.
 *
 * @return mixed
 *   One of these possibilities:
 *   - If it succeeds and $managed is FALSE, the location where the file was
 *     saved.
 *   - If it succeeds and $managed is TRUE, a \Drupal\file\FileInterface
 *     object which describes the file.
 *   - If it fails, FALSE.
 */
function system_retrieve_file($url, $destination = NULL, $managed = FALSE, $replace = FILE_EXISTS_RENAME) {
  $parsed_url = parse_url($url);
  if (!isset($destination)) {
    $path = file_build_uri(drupal_basename($parsed_url['path']));
  }
  else {
    if (is_dir(drupal_realpath($destination))) {
      // Prevent URIs with triple slashes when glueing parts together.
      $path = str_replace('///', '//', "$destination/") . drupal_basename($parsed_url['path']);
    }
    else {
      $path = $destination;
    }
  }
  try {
    $data = (string) \Drupal::httpClient()
      ->get($url)
      ->getBody();
    $local = $managed ? file_save_data($data, $path, $replace) : file_unmanaged_save_data($data, $path, $replace);
  }
  catch (RequestException $exception) {
    drupal_set_message(t('Failed to fetch file due to error "%error"', array('%error' => $exception->getMessage())), 'error');
    return FALSE;
  }
  if (!$local) {
    drupal_set_message(t('@remote could not be saved to @path.', array('@remote' => $url, '@path' => $path)), 'error');
  }

  return $local;
}

/**
 * Implements hook_entity_type_build().
 */
function system_entity_type_build(array &$entity_types) {
  /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
  $entity_types['date_format']
    ->setFormClass('add', 'Drupal\system\Form\DateFormatAddForm')
    ->setFormClass('edit', 'Drupal\system\Form\DateFormatEditForm')
    ->setFormClass('delete', 'Drupal\system\Form\DateFormatDeleteForm')
    ->setListBuilderClass('Drupal\system\DateFormatListBuilder')
    ->setLinkTemplate('edit-form', '/admin/config/regional/date-time/formats/manage/{date_format}')
    ->setLinkTemplate('delete-form', '/admin/config/regional/date-time/formats/manage/{date_format}/delete')
    ->setLinkTemplate('collection', '/admin/config/regional/date-time/formats');
}

/**
 * Implements hook_block_view_BASE_BLOCK_ID_alter().
 */
function system_block_view_system_main_block_alter(array &$build, BlockPluginInterface $block) {
  // Contextual links on the system_main block would basically duplicate the
  // tabs/local tasks, so reduce the clutter.
  unset($build['#contextual_links']);
}

/**
 * Implements hook_path_update().
 */
function system_path_update() {
  \Drupal::service('path.alias_manager')->cacheClear();
}

/**
 * Implements hook_path_insert().
 */
function system_path_insert() {
  \Drupal::service('path.alias_manager')->cacheClear();
}

/**
 * Implements hook_path_delete().
 */
function system_path_delete($path) {
  \Drupal::service('path.alias_manager')->cacheClear();
}

/**
 * Implements hook_query_TAG_alter() for entity reference selection handlers.
 */
function system_query_entity_reference_alter(AlterableInterface $query) {
  $handler = $query->getMetadata('entity_reference_selection_handler');
  $handler->entityQueryAlter($query);
}