You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

410 lines
13KB

  1. <?php
  2. /**
  3. * @file
  4. * Enables modules and site configuration for a thunder site installation.
  5. */
  6. use Drupal\Core\Entity\EntityStorageException;
  7. use Drupal\Core\Entity\EntityTypeInterface;
  8. use Drupal\Core\Form\FormStateInterface;
  9. use Drupal\block\Entity\Block;
  10. use Drupal\Core\Installer\InstallerKernel;
  11. use Drupal\user\Entity\User;
  12. use Drupal\user\Entity\Role;
  13. /**
  14. * Implements hook_form_FORM_ID_alter() for install_configure_form().
  15. *
  16. * Allows the profile to alter the site configuration form.
  17. */
  18. function thunder_form_install_configure_form_alter(&$form, FormStateInterface $form_state) {
  19. // Add a value as example that one can choose an arbitrary site name.
  20. $form['site_information']['site_name']['#placeholder'] = t('Thunder');
  21. }
  22. /**
  23. * Implements hook_install_tasks().
  24. */
  25. function thunder_install_tasks(&$install_state) {
  26. $tasks = [];
  27. if (empty($install_state['config_install_path'])) {
  28. $tasks['thunder_module_configure_form'] = [
  29. 'display_name' => t('Configure additional modules'),
  30. 'type' => 'form',
  31. 'function' => 'Drupal\thunder\Installer\Form\ModuleConfigureForm',
  32. ];
  33. $tasks['thunder_module_install'] = [
  34. 'display_name' => t('Install additional modules'),
  35. 'type' => 'batch',
  36. ];
  37. }
  38. $tasks['thunder_finish_installation'] = [
  39. 'display_name' => t('Finish installation'),
  40. ];
  41. return $tasks;
  42. }
  43. /**
  44. * Installs the thunder modules in a batch.
  45. *
  46. * @param array $install_state
  47. * The install state.
  48. *
  49. * @return array
  50. * A batch array to execute.
  51. */
  52. function thunder_module_install(array &$install_state) {
  53. $modules = $install_state['thunder_additional_modules'];
  54. $batch = [];
  55. if ($modules) {
  56. $operations = [];
  57. foreach ($modules as $module) {
  58. $operations[] = [
  59. '_thunder_install_module_batch',
  60. [[$module], $module, $install_state['form_state_values']],
  61. ];
  62. }
  63. $batch = [
  64. 'operations' => $operations,
  65. 'title' => t('Installing additional modules'),
  66. 'error_message' => t('The installation has encountered an error.'),
  67. ];
  68. }
  69. return $batch;
  70. }
  71. /**
  72. * Implements callback_batch_operation().
  73. *
  74. * Performs batch installation of modules.
  75. */
  76. function _thunder_install_module_batch($module, $module_name, $form_values, &$context) {
  77. set_time_limit(0);
  78. $optionalModulesManager = \Drupal::service('plugin.manager.thunder.optional_modules');
  79. try {
  80. $definition = $optionalModulesManager->getDefinition($module_name);
  81. if ($definition['type'] == 'module') {
  82. \Drupal::service('module_installer')->install($module, TRUE);
  83. }
  84. elseif ($definition['type'] == 'theme') {
  85. \Drupal::service('theme_installer')->install($module, TRUE);
  86. }
  87. $instance = $optionalModulesManager->createInstance($module_name);
  88. $instance->submitForm($form_values);
  89. }
  90. catch (\Exception $e) {
  91. }
  92. $context['results'][] = $module;
  93. $context['message'] = t('Installed %module_name modules.', ['%module_name' => $module_name]);
  94. }
  95. /**
  96. * Finish Thunder installation process.
  97. *
  98. * @param array $install_state
  99. * The install state.
  100. *
  101. * @throws \Drupal\Core\Entity\EntityStorageException
  102. */
  103. function thunder_finish_installation(array &$install_state) {
  104. \Drupal::service('config.installer')->installOptionalConfig();
  105. // Assign user 1 the "administrator" role.
  106. $user = User::load(1);
  107. $user->roles[] = 'administrator';
  108. $user->save();
  109. }
  110. /**
  111. * Implements hook_themes_installed().
  112. */
  113. function thunder_themes_installed($theme_list) {
  114. if (in_array('thunder_amp', $theme_list)) {
  115. // Install AMP module.
  116. \Drupal::service('module_installer')->install(['amp'], TRUE);
  117. \Drupal::configFactory()
  118. ->getEditable('amp.settings')
  119. ->set('amp_library_process_full_html', TRUE)
  120. ->save(TRUE);
  121. // Set AMP theme to thunder_amp,
  122. // if not set, or is one of the included themes.
  123. $ampThemeConfig = \Drupal::configFactory()->getEditable('amp.theme');
  124. $ampTheme = $ampThemeConfig->get('amptheme');
  125. if (empty($ampTheme) || $ampTheme == 'ampsubtheme_example' || $ampTheme == 'amptheme') {
  126. $ampThemeConfig->set('amptheme', 'thunder_amp')
  127. ->save(TRUE);
  128. }
  129. // Disable unused blocks.
  130. /** @var \Drupal\block\Entity\Block[] $blocks */
  131. $blocks = Block::loadMultiple([
  132. 'thunder_amp_account_menu',
  133. 'thunder_amp_breadcrumbs',
  134. 'thunder_amp_footer',
  135. 'thunder_amp_local_actions',
  136. 'thunder_amp_local_tasks',
  137. 'thunder_amp_main_menu',
  138. 'thunder_amp_messages',
  139. 'thunder_amp_tools',
  140. ]);
  141. foreach ($blocks as $block) {
  142. $block->disable()->save();
  143. }
  144. }
  145. if (in_array('amptheme', $theme_list)) {
  146. \Drupal::service('module_installer')->install(['amp'], TRUE);
  147. }
  148. }
  149. /**
  150. * Check if provided triggering modules are one of the newly installed modules.
  151. *
  152. * This function is helper for thunder_modules_installed(). Using it in another
  153. * context is not recommended. @see hook_modules_installed()
  154. *
  155. * @param array $modules
  156. * The list of the modules that were newly installed.
  157. * @param array $triggering_modules
  158. * The list of triggering modules required for executing some action.
  159. *
  160. * @return bool
  161. * Returns if triggering module is newly installed.
  162. */
  163. function _thunder_check_triggering_modules(array $modules, array $triggering_modules) {
  164. // Check that at least one triggering module is in list of the modules that
  165. // were newly installed.
  166. $triggering_not_installed_modules = array_diff($triggering_modules, $modules);
  167. if (count($triggering_not_installed_modules) === count($triggering_modules)) {
  168. return FALSE;
  169. }
  170. // All required triggering modules are in the list of the modules that were
  171. // newly installed.
  172. if (empty($triggering_not_installed_modules)) {
  173. return TRUE;
  174. }
  175. /** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */
  176. $module_handler = Drupal::moduleHandler();
  177. $active_modules = array_keys($module_handler->getModuleList());
  178. // Ensure that all triggering modules modules are installed on system.
  179. $required_not_active_modules = array_diff($triggering_not_installed_modules, $active_modules);
  180. return empty($required_not_active_modules);
  181. }
  182. /**
  183. * Check if enabling of a module is executed.
  184. *
  185. * This function is helper for thunder_modules_installed(). Using it in another
  186. * context is not recommended. @see hook_modules_installed()
  187. *
  188. * @return bool
  189. * Returns if enabling of a module is currently running.
  190. */
  191. function _thunder_is_enabling_module() {
  192. return !InstallerKernel::installationAttempted() && !Drupal::isConfigSyncing();
  193. }
  194. /**
  195. * Implements hook_modules_installed().
  196. */
  197. function thunder_modules_installed($modules) {
  198. if (
  199. _thunder_is_enabling_module()
  200. && _thunder_check_triggering_modules($modules, ['content_moderation', 'config_update'])
  201. ) {
  202. if (!Role::load('restricted_editor')) {
  203. /** @var Drupal\config_update\ConfigRevertInterface $configReverter */
  204. $configReverter = \Drupal::service('config_update.config_update');
  205. $configReverter->import('user_role', 'restricted_editor');
  206. }
  207. // Granting permissions only for "editor" and "seo" user roles.
  208. $roles = Role::loadMultiple(['editor', 'seo']);
  209. foreach ($roles as $role) {
  210. try {
  211. $role->grantPermission('use editorial transition create_new_draft');
  212. $role->grantPermission('use editorial transition publish');
  213. $role->grantPermission('use editorial transition unpublish');
  214. $role->grantPermission('use editorial transition unpublished_draft');
  215. $role->grantPermission('use editorial transition unpublished_published');
  216. $role->grantPermission('view any unpublished content');
  217. $role->grantPermission('view latest version');
  218. $role->save();
  219. }
  220. catch (EntityStorageException $storageException) {
  221. }
  222. }
  223. }
  224. if (
  225. _thunder_is_enabling_module()
  226. && _thunder_check_triggering_modules($modules, ['content_moderation', 'scheduler'])
  227. ) {
  228. \Drupal::service('module_installer')->install(['scheduler_content_moderation_integration']);
  229. }
  230. // When enabling password policy, enabled required sub modules.
  231. if (
  232. _thunder_is_enabling_module()
  233. && _thunder_check_triggering_modules($modules, ['password_policy'])
  234. ) {
  235. \Drupal::service('module_installer')->install(['password_policy_length']);
  236. \Drupal::service('module_installer')->install(['password_policy_history']);
  237. \Drupal::service('module_installer')->install(['password_policy_character_types']);
  238. \Drupal::service('messenger')->addStatus(t('The Password Character Length, Password Policy History and Password Character Types modules have been additionally enabled, they are required by the default policy configuration.'));
  239. }
  240. // Move fields into form display.
  241. if (_thunder_check_triggering_modules($modules, ['ivw_integration'])) {
  242. $fieldWidget = 'ivw_integration_widget';
  243. // Attach field if channel vocabulary and article node type is
  244. // present in the distribution.
  245. try {
  246. \Drupal::service('entity_display.repository')
  247. ->getFormDisplay('node', 'article', 'default')
  248. ->setComponent(
  249. 'field_ivw', [
  250. 'type' => $fieldWidget,
  251. ])->save();
  252. }
  253. catch (Exception $e) {
  254. \Drupal::logger('thunder')->info(t('Could not add ivw field to article node: "@message"', ['@message' => $e->getMessage()]));
  255. }
  256. try {
  257. \Drupal::service('entity_display.repository')
  258. ->getFormDisplay('taxonomy_term', 'channel', 'default')
  259. ->setComponent('field_ivw', [
  260. 'type' => $fieldWidget,
  261. ])->save();
  262. }
  263. catch (Exception $e) {
  264. \Drupal::logger('thunder')->info(t('Could not add ivw field to channel taxonomy: "@message"', ['@message' => $e->getMessage()]));
  265. }
  266. }
  267. // When enabling content_translation, grant permissions to Thunder user roles.
  268. if (_thunder_check_triggering_modules($modules, ['content_translation'])) {
  269. /** @var \Drupal\user\Entity\Role[] $roles */
  270. $roles = Role::loadMultiple(['editor', 'seo', 'restricted_editor']);
  271. foreach ($roles as $role) {
  272. try {
  273. $role->grantPermission('create content translations');
  274. $role->grantPermission('update content translations');
  275. $role->grantPermission('translate any entity');
  276. if (in_array($role->id(), ['editor', 'seo'])) {
  277. $role->grantPermission('delete content translations');
  278. }
  279. $role->save();
  280. }
  281. catch (EntityStorageException $storageException) {
  282. }
  283. }
  284. }
  285. }
  286. /**
  287. * Implements hook_modules_uninstalled().
  288. */
  289. function thunder_modules_uninstalled($modules) {
  290. // Import the content view if it was deleted during module uninstalling.
  291. // This could happen if content_lock was uninstalled and the content view
  292. // contained content_lock fields at that time.
  293. if (in_array('content_lock', $modules, TRUE)) {
  294. /** @var \Drupal\Core\Routing\RouteProviderInterface $route_provider */
  295. $route_provider = \Drupal::service('router.route_provider');
  296. $found_routes = $route_provider->getRoutesByPattern('admin/content');
  297. $view_found = FALSE;
  298. foreach ($found_routes->getIterator() as $route) {
  299. if (!empty($route->getDefault('view_id'))) {
  300. $view_found = TRUE;
  301. break;
  302. }
  303. }
  304. if (!$view_found) {
  305. $config_service = \Drupal::service('config_update.config_update');
  306. $config_service->import('view', 'content');
  307. }
  308. }
  309. }
  310. /**
  311. * Implements hook_page_attachments().
  312. */
  313. function thunder_page_attachments(array &$attachments) {
  314. foreach ($attachments['#attached']['html_head'] as &$html_head) {
  315. $name = $html_head[1];
  316. if ($name == 'system_meta_generator') {
  317. $tag = &$html_head[0];
  318. $tag['#attributes']['content'] = 'Drupal 8 (Thunder | http://www.thunder.org)';
  319. }
  320. }
  321. }
  322. /**
  323. * Implements hook_library_info_alter().
  324. */
  325. function thunder_toolbar_alter(&$items) {
  326. if (!empty($items['admin_toolbar_tools'])) {
  327. $items['admin_toolbar_tools']['#attached']['library'][] = 'thunder/toolbar.icon';
  328. }
  329. }
  330. /**
  331. * Implements hook_entity_base_field_info_alter().
  332. */
  333. function thunder_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
  334. if (\Drupal::config('system.theme')->get('admin') == 'thunder_admin' && \Drupal::hasService('content_moderation.moderation_information')) {
  335. /** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */
  336. $moderation_info = \Drupal::service('content_moderation.moderation_information');
  337. if ($moderation_info->canModerateEntitiesOfEntityType($entity_type) && isset($fields['moderation_state'])) {
  338. $fields['moderation_state']->setDisplayOptions('form', [
  339. 'type' => 'thunder_moderation_state_default',
  340. 'weight' => 100,
  341. 'settings' => [],
  342. ]);
  343. }
  344. }
  345. }
  346. /**
  347. * Implements hook_field_widget_info_alter().
  348. */
  349. function thunder_field_widget_info_alter(array &$info) {
  350. if (!\Drupal::moduleHandler()->moduleExists('content_moderation')) {
  351. unset($info['thunder_moderation_state_default']);
  352. }
  353. }
  354. /**
  355. * Implements hook_field_widget_multivalue_WIDGET_TYPE_form_alter().
  356. *
  357. * Removes the cardinality information from the #prefix element of the current
  358. * selection.
  359. */
  360. function thunder_field_widget_multivalue_entity_browser_entity_reference_form_alter(array &$elements, FormStateInterface $form_state, array $context) {
  361. unset($elements['current']['#prefix']);
  362. }