diff --git a/core/modules/media_library/media_library.install b/core/modules/media_library/media_library.install index f91d2ec682..8611a83313 100644 --- a/core/modules/media_library/media_library.install +++ b/core/modules/media_library/media_library.install @@ -5,6 +5,8 @@ * Install, update and uninstall functions for the media_library module. */ +use Drupal\Core\Config\FileStorage; +use Drupal\Core\Config\InstallStorage; use Drupal\media\Entity\MediaType; use Drupal\views\Entity\View; @@ -12,21 +14,53 @@ * Implements hook_install(). */ function media_library_install() { - // Change the path to the original media view. + // This hook heavily modifies configuration, which should not be done during a + // config sync. + if (\Drupal::isConfigSyncing()) { + return; + } + + // Modify the 'media' view, respecting pre-existing customizations. /** @var \Drupal\views\Entity\View $view */ if ($view = View::load('media')) { $display = &$view->getDisplay('media_page_list'); - if (!empty($display)) { - $display['display_options']['path'] = 'admin/content/media-table'; - unset($display['display_options']['menu']); + if ($display && $display['display_plugin'] === 'page') { + $defaults = _media_library_read_default_media_view(); + + // Change the path, if it hasn't already been changed by the site builder. + if ($display['display_options']['path'] === $defaults['display_options']['path']) { + $display['display_options']['path'] .= '-table'; + } + + // If the default menu options are being used, remove the menu item. + if (isset($display['display_options']['menu'])) { + // In comparing the current menu settings to the default one, only + // consider settings that affect the type of the menu link, or where it + // is in the menu tree. + $default_menu_settings = [ + 'type' => $defaults['display_options']['menu']['type'], + 'parent' => $defaults['display_options']['menu']['parent'], + 'menu_name' => $defaults['display_options']['menu']['menu_name'], + ]; + $current_menu_settings = array_intersect_key($display['display_options']['menu'], $default_menu_settings); + + // Sort the settings arrays by key so they can be compared with ===. + ksort($default_menu_settings); + ksort($current_menu_settings); + + // If the current menu settings have the same link type and placement as + // shipped with the Media module, remove the link. + if ($current_menu_settings === $default_menu_settings) { + unset($display['display_options']['menu']); + } + } $view->trustData()->save(); } } - if (!\Drupal::isConfigSyncing()) { - foreach (MediaType::loadMultiple() as $type) { - _media_library_configure_form_display($type); - _media_library_configure_view_display($type); - } + + foreach (MediaType::loadMultiple() as $type) { + _media_library_configure_form_display($type); + _media_library_configure_view_display($type); } } @@ -34,27 +68,40 @@ function media_library_install() { * Implements hook_uninstall(). */ function media_library_uninstall() { - // Restore the path to the original media view. + // Undo changes to the 'media' view made by media_library_install(). /** @var \Drupal\views\Entity\View $view */ if ($view = View::load('media')) { $display = &$view->getDisplay('media_page_list'); - if (!empty($display)) { - $display['display_options']['path'] = 'admin/content/media'; - $display['display_options']['menu'] = [ - 'type' => 'tab', - 'title' => 'Media', - 'description' => '', - 'expanded' => FALSE, - 'parent' => '', - 'weight' => 0, - 'context' => '0', - 'menu_name' => 'main', - ]; + if ($display && $display['display_plugin'] === 'page') { + $defaults = _media_library_read_default_media_view(); + + if ($display['display_options']['path'] === $defaults['display_options']['path'] . '-table') { + $display['display_options']['path'] = $defaults['display_options']['path']; + } + if (!isset($display['display_options']['menu'])) { + $display['display_options']['menu'] = $defaults['display_options']['menu']; + } $view->trustData()->save(); } } } +/** + * Reads the default configuration of the 'media' view. + * + * @return array + * The default configuration of the 'media_page_list' display of the 'media' + * view, as shipped in the Media module's optional config. + */ +function _media_library_read_default_media_view() { + $directory = \Drupal::service('extension.list.module') + ->get('media') + ->getPath(); + + $storage = new FileStorage($directory . '/' . InstallStorage::CONFIG_OPTIONAL_DIRECTORY); + return $storage->read('views.view.media')['display']['media_page_list']; +} + /** * Create the 'media_library' image style. */ diff --git a/core/modules/media_library/tests/src/Functional/InstallUninstallTest.php b/core/modules/media_library/tests/src/Functional/InstallUninstallTest.php new file mode 100644 index 0000000000..22086e2fb1 --- /dev/null +++ b/core/modules/media_library/tests/src/Functional/InstallUninstallTest.php @@ -0,0 +1,249 @@ +drupalPlaceBlock('local_tasks_block'); + + $account = $this->drupalCreateUser([ + 'access administration pages', + 'access media overview', + ]); + $this->drupalLogin($account); + } + + /** + * Tests expected changes when the 'media' view has not been customized. + */ + public function testWithoutCustomizations() { + $assert_session = $this->assertSession(); + + $this->drupalGet('/admin/content/media'); + $assert_session->elementExists('css', '.view-id-media'); + $assert_session->linkNotExists('Grid'); + $assert_session->linkNotExists('Table'); + $this->drupalGet('/admin/content/media-table'); + $assert_session->statusCodeEquals(404); + + $this->container->get('module_installer')->install(['media_library']); + + $view = View::load('media'); + $display = $view->getDisplay('media_page_list'); + $this->assertSame('admin/content/media-table', $display['display_options']['path']); + $this->assertArrayNotHasKey('menu', $display['display_options']); + + $this->drupalGet('/admin/content/media'); + $assert_session->elementExists('css', '.view-id-media_library'); + $assert_session->linkExists('Grid'); + $this->getSession()->getPage()->clickLink('Table'); + $assert_session->addressEquals('/admin/content/media-table'); + $assert_session->elementExists('css', '.view-id-media'); + + $this->container->get('module_installer')->uninstall(['media_library']); + + $view = View::load('media'); + $display = $view->getDisplay('media_page_list'); + $this->assertSame('admin/content/media', $display['display_options']['path']); + $this->assertSame('tab', $display['display_options']['menu']['type']); + $this->assertSame('', $display['display_options']['menu']['parent']); + $this->assertSame('main', $display['display_options']['menu']['menu_name']); + + // Things should be as they were before Media Library was installed. + $this->drupalGet('/admin/content/media'); + $assert_session->elementExists('css', '.view-id-media'); + $assert_session->linkNotExists('Grid'); + $assert_session->linkNotExists('Table'); + $this->drupalGet('/admin/content/media-table'); + $assert_session->statusCodeEquals(404); + } + + /** + * Tests that a custom path to the media view's page display is not modified. + */ + public function testCustomizedAdministrationPagePath() { + $assert_session = $this->assertSession(); + + // If the media view's page display's path has been changed before Media + // Library is installed, it should not be changed by hook_install(). + $view = View::load('media'); + + $display = &$view->getDisplay('media_page_list'); + $display['display_options']['path'] = '/admin/content/all-media'; + $view->save(); + + $this->container->get('module_installer')->install(['media_library']); + + $view = View::load('media'); + $display = $view->getDisplay('media_page_list'); + $this->assertSame('/admin/content/all-media', $display['display_options']['path']); + + $this->drupalGet('/admin/content/media'); + $assert_session->elementExists('css', '.view-id-media_library'); + $this->drupalGet('/admin/content/media-table'); + $assert_session->statusCodeEquals(404); + $this->drupalGet('/admin/content/all-media'); + $assert_session->elementExists('css', '.view-id-media'); + $this->drupalGet('/admin/content/all-media-table'); + $assert_session->statusCodeEquals(404); + + $this->container->get('module_installer')->uninstall(['media_library']); + + $view = View::load('media'); + $display = $view->getDisplay('media_page_list'); + $this->assertSame('/admin/content/all-media', $display['display_options']['path']); + $this->assertSame('tab', $display['display_options']['menu']['type']); + $this->assertSame('', $display['display_options']['menu']['parent']); + $this->assertSame('main', $display['display_options']['menu']['menu_name']); + + // This will be a 403 because uninstalling media_library removed the + // /admin/content/media path -- the 'media' view lives at + // /admin/content/all-media, remember -- and therefore, /admin/content/media + // is going to go to the Media entity's list builder, which requires the + // 'administer media' permission...which the current user doesn't have. + $this->drupalGet('/admin/content/media'); + $assert_session->statusCodeEquals(403); + $this->drupalGet('/admin/content/media-table'); + $assert_session->statusCodeEquals(404); + $this->drupalGet('/admin/content/all-media'); + $assert_session->elementExists('css', '.view-id-media'); + $this->drupalGet('/admin/content/all-media-table'); + $assert_session->statusCodeEquals(404); + } + + /** + * Tests that a custom link to the media view's page display is not modified. + */ + public function testCustomizedMenuSettings() { + $assert_session = $this->assertSession(); + $page = $this->getSession()->getPage(); + + // If the media view's page display's menu settings have been changed before + // Media Library is installed, they should not be changed by hook_install(). + $view = View::load('media'); + + $display = &$view->getDisplay('media_page_list'); + $display['display_options']['menu']['title'] = 'A treasure trove of interesting pictures!'; + $display['display_options']['menu']['type'] = 'normal'; + $display['display_options']['menu']['parent'] = 'system.admin_structure'; + $view->save(); + + $this->container->get('module_installer')->install(['media_library']); + + $view = View::load('media'); + $display = $view->getDisplay('media_page_list'); + $this->assertSame('admin/content/media-table', $display['display_options']['path']); + $this->assertSame('normal', $display['display_options']['menu']['type']); + $this->assertSame('system.admin_structure', $display['display_options']['menu']['parent']); + $this->assertSame('main', $display['display_options']['menu']['menu_name']); + + $this->drupalGet('/admin/structure'); + $page->clickLink('A treasure trove of interesting pictures!'); + $assert_session->addressEquals('/admin/content/media-table'); + $page->clickLink('Grid'); + $assert_session->addressEquals('/admin/content/media'); + + $this->container->get('module_installer')->uninstall(['media_library']); + + $view = View::load('media'); + $display = $view->getDisplay('media_page_list'); + $this->assertSame('admin/content/media', $display['display_options']['path']); + $this->assertSame('normal', $display['display_options']['menu']['type']); + $this->assertSame('system.admin_structure', $display['display_options']['menu']['parent']); + $this->assertSame('main', $display['display_options']['menu']['menu_name']); + + $this->drupalGet('/admin/structure'); + $page->clickLink('A treasure trove of interesting pictures!'); + $assert_session->addressEquals('/admin/content/media'); + $assert_session->linkNotExists('Grid'); + } + + /** + * Tests expected changes when the 'media' view has been heavily customized. + */ + public function testCustomizedAdministrationPagePathAndMenuSettings() { + $assert_session = $this->assertSession(); + $page = $this->getSession()->getPage(); + + // If the media view's page display's path has been changed before Media + // Library is installed, it should not be changed by hook_install(). + $view = View::load('media'); + + $display = &$view->getDisplay('media_page_list'); + $display['display_options']['path'] = '/admin/content/all-media'; + $display['display_options']['menu']['title'] = 'A treasure trove of interesting pictures!'; + $display['display_options']['menu']['type'] = 'normal'; + $display['display_options']['menu']['parent'] = 'system.admin_structure'; + $view->save(); + + $this->container->get('module_installer')->install(['media_library']); + + $view = View::load('media'); + $display = $view->getDisplay('media_page_list'); + $this->assertSame('/admin/content/all-media', $display['display_options']['path']); + $this->assertSame('normal', $display['display_options']['menu']['type']); + $this->assertSame('system.admin_structure', $display['display_options']['menu']['parent']); + $this->assertSame('main', $display['display_options']['menu']['menu_name']); + + $this->drupalGet('/admin/content/media'); + $assert_session->elementExists('css', '.view-id-media_library'); + $this->drupalGet('/admin/content/all-media'); + $assert_session->elementExists('css', '.view-id-media'); + $this->drupalGet('/admin/content/media-table'); + $assert_session->statusCodeEquals(404); + $this->drupalGet('/admin/content/all-media-table'); + $assert_session->statusCodeEquals(404); + + $this->drupalGet('/admin/structure'); + $page->clickLink('A treasure trove of interesting pictures!'); + $assert_session->addressEquals('/admin/content/all-media'); + $page->clickLink('Grid'); + $assert_session->addressEquals('/admin/content/media'); + $page->clickLink('Table'); + $assert_session->addressEquals('/admin/content/all-media'); + + $this->container->get('module_installer')->uninstall(['media_library']); + + $view = View::load('media'); + $display = $view->getDisplay('media_page_list'); + $this->assertSame('/admin/content/all-media', $display['display_options']['path']); + $this->assertSame('normal', $display['display_options']['menu']['type']); + $this->assertSame('system.admin_structure', $display['display_options']['menu']['parent']); + $this->assertSame('main', $display['display_options']['menu']['menu_name']); + + // @see ::testCustomizedAdministrationPagePath() for why this is a 403. + $this->drupalGet('/admin/content/media'); + $assert_session->statusCodeEquals(403); + $this->drupalGet('/admin/content/media-table'); + $assert_session->statusCodeEquals(404); + $this->drupalGet('/admin/content/all-media-table'); + $assert_session->statusCodeEquals(404); + $this->drupalGet('/admin/content/all-media'); + $assert_session->elementExists('css', '.view-id-media'); + + $this->drupalGet('/admin/structure'); + $page->clickLink('A treasure trove of interesting pictures!'); + $assert_session->addressEquals('/admin/content/all-media'); + $assert_session->linkNotExists('Grid'); + $assert_session->linkNotExists('Table'); + } + +}