From bdbbb0462ed0d888364d9f4dec4878c399415e67 Mon Sep 17 00:00:00 2001 From: phenaproxima <phenaproxima@205645.no-reply.drupal.org> Date: Wed, 11 May 2022 20:02:52 +0000 Subject: [PATCH] Issue #3279527 by phenaproxima, tedbow: Ensure plugins are reloaded after an update --- .../1.0.0/src/Plugin/Block/DeletedBlock.php | 26 ++++++++++ .../1.0.0/src/Plugin/Block/IgnoredBlock.php | 29 +++++++++++ .../1.0.0/src/Plugin/Block/UpdatedBlock.php | 29 +++++++++++ .../1.1.0/src/Plugin/Block/AddedBlock.php | 26 ++++++++++ .../1.1.0/src/Plugin/Block/IgnoredBlock.php | 29 +++++++++++ .../1.1.0/src/Plugin/Block/UpdatedBlock.php | 29 +++++++++++ .../package_manager_test_api.services.yml | 1 + .../src/SystemChangeRecorder.php | 48 ++++++++++++++++++- .../tests/src/Build/PackageUpdateTest.php | 27 +++++++++++ 9 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 package_manager/tests/fixtures/updated_module/1.0.0/src/Plugin/Block/DeletedBlock.php create mode 100644 package_manager/tests/fixtures/updated_module/1.0.0/src/Plugin/Block/IgnoredBlock.php create mode 100644 package_manager/tests/fixtures/updated_module/1.0.0/src/Plugin/Block/UpdatedBlock.php create mode 100644 package_manager/tests/fixtures/updated_module/1.1.0/src/Plugin/Block/AddedBlock.php create mode 100644 package_manager/tests/fixtures/updated_module/1.1.0/src/Plugin/Block/IgnoredBlock.php create mode 100644 package_manager/tests/fixtures/updated_module/1.1.0/src/Plugin/Block/UpdatedBlock.php diff --git a/package_manager/tests/fixtures/updated_module/1.0.0/src/Plugin/Block/DeletedBlock.php b/package_manager/tests/fixtures/updated_module/1.0.0/src/Plugin/Block/DeletedBlock.php new file mode 100644 index 0000000000..e4c501b199 --- /dev/null +++ b/package_manager/tests/fixtures/updated_module/1.0.0/src/Plugin/Block/DeletedBlock.php @@ -0,0 +1,26 @@ +<?php + +namespace Drupal\updated_module\Plugin\Block; + +use Drupal\Core\Block\BlockBase; + +/** + * This block is removed from version 1.1.0 of this module. + * + * @Block( + * id = "updated_module_deleted_block", + * admin_label = @Translation("Deleted block"), + * ) + */ +class DeletedBlock extends BlockBase { + + /** + * {@inheritdoc} + */ + public function build() { + return [ + '#markup' => $this->t('Goodbye!'), + ]; + } + +} diff --git a/package_manager/tests/fixtures/updated_module/1.0.0/src/Plugin/Block/IgnoredBlock.php b/package_manager/tests/fixtures/updated_module/1.0.0/src/Plugin/Block/IgnoredBlock.php new file mode 100644 index 0000000000..ce7682274a --- /dev/null +++ b/package_manager/tests/fixtures/updated_module/1.0.0/src/Plugin/Block/IgnoredBlock.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\updated_module\Plugin\Block; + +use Drupal\Core\Block\BlockBase; + +/** + * Defines a block plugin to test plugin reloading during an update. + * + * This block should NOT be loaded before updating to version 1.1.0 of this + * module. + * + * @Block( + * id = "updated_module_ignored_block", + * admin_label = @Translation("1.0.0") + * ) + */ +class IgnoredBlock extends BlockBase { + + /** + * {@inheritdoc} + */ + public function build() { + return [ + '#markup' => $this->t("I should not be instantiated before the update."), + ]; + } + +} diff --git a/package_manager/tests/fixtures/updated_module/1.0.0/src/Plugin/Block/UpdatedBlock.php b/package_manager/tests/fixtures/updated_module/1.0.0/src/Plugin/Block/UpdatedBlock.php new file mode 100644 index 0000000000..4ac05fbc58 --- /dev/null +++ b/package_manager/tests/fixtures/updated_module/1.0.0/src/Plugin/Block/UpdatedBlock.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\updated_module\Plugin\Block; + +use Drupal\Core\Block\BlockBase; + +/** + * Defines a block plugin to test plugin reloading during an update. + * + * In version 1.1.0 of this module, this block exists but its plugin definition + * and implementation are different. + * + * @Block( + * id = "updated_module_updated_block", + * admin_label = @Translation("1.0.0") + * ) + */ +class UpdatedBlock extends BlockBase { + + /** + * {@inheritdoc} + */ + public function build() { + return [ + '#markup' => $this->t('1.0.0'), + ]; + } + +} diff --git a/package_manager/tests/fixtures/updated_module/1.1.0/src/Plugin/Block/AddedBlock.php b/package_manager/tests/fixtures/updated_module/1.1.0/src/Plugin/Block/AddedBlock.php new file mode 100644 index 0000000000..fd41ce3468 --- /dev/null +++ b/package_manager/tests/fixtures/updated_module/1.1.0/src/Plugin/Block/AddedBlock.php @@ -0,0 +1,26 @@ +<?php + +namespace Drupal\updated_module\Plugin\Block; + +use Drupal\Core\Block\BlockBase; + +/** + * This block doesn't exist in version 1.0.0 of this module. + * + * @Block( + * id = "updated_module_added_block", + * admin_label = @Translation("Added block"), + * ) + */ +class AddedBlock extends BlockBase { + + /** + * {@inheritdoc} + */ + public function build() { + return [ + '#markup' => $this->t('Hello!'), + ]; + } + +} diff --git a/package_manager/tests/fixtures/updated_module/1.1.0/src/Plugin/Block/IgnoredBlock.php b/package_manager/tests/fixtures/updated_module/1.1.0/src/Plugin/Block/IgnoredBlock.php new file mode 100644 index 0000000000..db675ccf76 --- /dev/null +++ b/package_manager/tests/fixtures/updated_module/1.1.0/src/Plugin/Block/IgnoredBlock.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\updated_module\Plugin\Block; + +use Drupal\Core\Block\BlockBase; + +/** + * Defines a block plugin to test plugin reloading during an update. + * + * This block should only be loaded and built after updating to version 1.1.0 of + * this module. + * + * @Block( + * id = "updated_module_ignored_block", + * admin_label = @Translation("1.1.0") + * ) + */ +class IgnoredBlock extends BlockBase { + + /** + * {@inheritdoc} + */ + public function build() { + return [ + '#markup' => $this->t('I was ignored before the update.'), + ]; + } + +} diff --git a/package_manager/tests/fixtures/updated_module/1.1.0/src/Plugin/Block/UpdatedBlock.php b/package_manager/tests/fixtures/updated_module/1.1.0/src/Plugin/Block/UpdatedBlock.php new file mode 100644 index 0000000000..fb014cb33b --- /dev/null +++ b/package_manager/tests/fixtures/updated_module/1.1.0/src/Plugin/Block/UpdatedBlock.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\updated_module\Plugin\Block; + +use Drupal\Core\Block\BlockBase; + +/** + * Defines a block plugin to test plugin reloading during an update. + * + * In version 1.0.0 of this module, this block exists but its plugin definition + * and implementation are different. + * + * @Block( + * id = "updated_module_updated_block", + * admin_label = @Translation("1.1.0") + * ) + */ +class UpdatedBlock extends BlockBase { + + /** + * {@inheritdoc} + */ + public function build() { + return [ + '#markup' => $this->t('1.1.0'), + ]; + } + +} diff --git a/package_manager/tests/modules/package_manager_test_api/package_manager_test_api.services.yml b/package_manager/tests/modules/package_manager_test_api/package_manager_test_api.services.yml index 6bf6af37d1..257393c899 100644 --- a/package_manager/tests/modules/package_manager_test_api/package_manager_test_api.services.yml +++ b/package_manager/tests/modules/package_manager_test_api/package_manager_test_api.services.yml @@ -6,5 +6,6 @@ services: - '@state' - '@router.no_access_checks' - '@user.permissions' + - '@plugin.manager.block' tags: - { name: event_subscriber } diff --git a/package_manager/tests/modules/package_manager_test_api/src/SystemChangeRecorder.php b/package_manager/tests/modules/package_manager_test_api/src/SystemChangeRecorder.php index a86a6c24f7..de50090860 100644 --- a/package_manager/tests/modules/package_manager_test_api/src/SystemChangeRecorder.php +++ b/package_manager/tests/modules/package_manager_test_api/src/SystemChangeRecorder.php @@ -2,6 +2,7 @@ namespace Drupal\package_manager_test_api; +use Drupal\Core\Block\BlockManagerInterface; use Drupal\Core\State\StateInterface; use Drupal\package_manager\Event\PostApplyEvent; use Drupal\package_manager\Event\PostDestroyEvent; @@ -45,6 +46,13 @@ class SystemChangeRecorder implements EventSubscriberInterface { */ private $permissionHandler; + /** + * The block plugin manager. + * + * @var \Drupal\Core\Block\BlockManagerInterface + */ + private $blockManager; + /** * Constructs a SystemChangeRecorder object. * @@ -56,12 +64,15 @@ class SystemChangeRecorder implements EventSubscriberInterface { * The router service. * @param \Drupal\user\PermissionHandlerInterface $permission_handler * The permission handler service. + * @param \Drupal\Core\Block\BlockManagerInterface $block_manager + * The block plugin manager. */ - public function __construct(PathLocator $path_locator, StateInterface $state, RouterInterface $router, PermissionHandlerInterface $permission_handler) { + public function __construct(PathLocator $path_locator, StateInterface $state, RouterInterface $router, PermissionHandlerInterface $permission_handler, BlockManagerInterface $block_manager) { $this->pathLocator = $path_locator; $this->state = $state; $this->router = $router; $this->permissionHandler = $permission_handler; + $this->blockManager = $block_manager; } /** @@ -106,6 +117,14 @@ class SystemChangeRecorder implements EventSubscriberInterface { $phase = $event instanceof PreApplyEvent ? 'pre' : 'post'; + // Check if changes to a block plugin's definition and implementation are + // picked up. + $this->recordBlockState('updated_module_deleted_block', $results, $phase === 'pre'); + $this->recordBlockState('updated_module_updated_block', $results, TRUE); + $this->recordBlockState('updated_module_added_block', $results, $phase === 'post'); + // Record the state of a block that was NOT instantiated before the update. + $this->recordBlockState('updated_module_ignored_block', $results, $phase === 'post'); + // Check if changes to an existing class are picked up. $this->recordClassValue('ChangedClass', $results); // Check if changes to a class that has not been loaded before the update is @@ -125,6 +144,33 @@ class SystemChangeRecorder implements EventSubscriberInterface { $this->state->set("system_changes:$phase", $results); } + /** + * Records the state of a block plugin. + * + * @param string $block_id + * Tbe block plugin ID. + * @param array $results + * The current set of results, passed by reference. + * @param bool $build + * Whether or not to instantiate the block plugin and include its output + * in the results. + */ + private function recordBlockState(string $block_id, array &$results, bool $build): void { + if ($this->blockManager->hasDefinition($block_id)) { + $results["$block_id block exists"] = 'exists'; + $plugin_definition = $this->blockManager->getDefinition($block_id); + $results["$block_id block label"] = (string) $plugin_definition['admin_label']; + + if ($build) { + $build = $this->blockManager->createInstance($block_id)->build(); + $results["$block_id block output"] = (string) $build['#markup']; + } + } + else { + $results["$block_id block exists"] = 'not exists'; + } + } + /** * Checks if a given class exists, and records its 'value' property. * diff --git a/package_manager/tests/src/Build/PackageUpdateTest.php b/package_manager/tests/src/Build/PackageUpdateTest.php index bb4485d099..f0016d4440 100644 --- a/package_manager/tests/src/Build/PackageUpdateTest.php +++ b/package_manager/tests/src/Build/PackageUpdateTest.php @@ -82,6 +82,16 @@ class PackageUpdateTest extends TemplateProjectTestBase { 'updated_module.deleted_service exists' => 'exists', 'value of updated_module.deleted_service' => 'Deleted service, should not exist after update', 'updated_module.added_service exists' => 'not exists', + 'updated_module_deleted_block block exists' => 'exists', + 'updated_module_deleted_block block label' => 'Deleted block', + 'updated_module_deleted_block block output' => 'Goodbye!', + 'updated_module_updated_block block exists' => 'exists', + 'updated_module_updated_block block label' => '1.0.0', + 'updated_module_updated_block block output' => '1.0.0', + 'updated_module_added_block block exists' => 'not exists', + // This block is not instantiated until the update is done. + 'updated_module_ignored_block block exists' => 'exists', + 'updated_module_ignored_block block label' => '1.0.0', 'ChangedClass exists' => 'exists', 'value of ChangedClass' => 'Before Update', 'LoadedAndDeletedClass exists' => 'exists', @@ -115,6 +125,23 @@ class PackageUpdateTest extends TemplateProjectTestBase { // the expected value. 'updated_module.added_service exists' => 'exists', 'value of updated_module.added_service' => 'New service, should not exist before update', + // A block removed from the updated module should not be defined anymore. + 'updated_module_deleted_block block exists' => 'not exists', + // A block that was updated should have a changed definition, but an + // unchanged implementation. + 'updated_module_updated_block block exists' => 'exists', + 'updated_module_updated_block block label' => '1.1.0', + 'updated_module_updated_block block output' => '1.0.0', + // A block added to the module should be defined. + 'updated_module_added_block block exists' => 'exists', + 'updated_module_added_block block label' => 'Added block', + 'updated_module_added_block block output' => 'Hello!', + // A block whose definition and implementation were updated, but was NOT + // instantiated before the update, should have an updated definition and + // implementation. + 'updated_module_ignored_block block exists' => 'exists', + 'updated_module_ignored_block block label' => '1.1.0', + 'updated_module_ignored_block block output' => 'I was ignored before the update.', // Existing class should be available. 'ChangedClass exists' => 'exists', // Existing class will still use the pre-update version. -- GitLab