core/modules/block/lib/Drupal/block/BlockBase.php | 26 ++++++++++++- .../book/Plugin/Block/BookNavigationBlock.php | 36 ++---------------- .../lib/Drupal/search/Form/SearchBlockForm.php | 9 +++++ .../Drupal/system/Plugin/Block/SystemHelpBlock.php | 22 +++++------ .../Drupal/system/Plugin/Block/SystemMenuBlock.php | 29 ++------------ .../UserLoginBlockConfigChangeSubscriber.php | 40 ++++++++++++++++++++ .../Drupal/user/Plugin/Block/UserLoginBlock.php | 9 +++++ core/modules/user/user.services.yml | 4 ++ 8 files changed, 104 insertions(+), 71 deletions(-) diff --git a/core/modules/block/lib/Drupal/block/BlockBase.php b/core/modules/block/lib/Drupal/block/BlockBase.php index 99150cf..2dd5cde 100644 --- a/core/modules/block/lib/Drupal/block/BlockBase.php +++ b/core/modules/block/lib/Drupal/block/BlockBase.php @@ -161,6 +161,18 @@ public function buildConfigurationForm(array $form, array &$form_state) { ), ), ); + if (count($this->getRequiredCacheContexts()) > 0) { + // Remove the required cache contexts from the list of contexts a user can + // choose to modify by: they must always be applied. + $context_labels = array(); + foreach ($this->getRequiredCacheContexts() as $context) { + $context_labels[] = $form['cache']['contexts']['#options'][$context]; + unset($form['cache']['contexts']['#options'][$context]); + } + $required_context_list = implode(', ', $context_labels); + $form['cache']['contexts']['#description'] .= ' ' . t('This block is always varied by the following contexts: %required-context-list.', array('%required-context-list' => $required_context_list)); + } + // Add plugin-specific settings for this block type. $form += $this->blockForm($form, $form_state); return $form; @@ -242,10 +254,22 @@ public function getMachineNameSuggestion() { } /** + * Returns the cache contexts required for this block. + * + * @return array + * The required cache contexts IDs. + */ + protected function getRequiredCacheContexts() { + return array(); + } + + /** * {@inheritdoc} */ public function getCacheKeys() { - return $this->configuration['cache']['contexts']; + // Return the required cache contexts, merged with the user-configured cache + // contexts, if any. + return array_merge($this->getRequiredCacheContexts(), $this->configuration['cache']['contexts']); } /** diff --git a/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php b/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php index 333a255..6a9cfff 100644 --- a/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php +++ b/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php @@ -155,40 +155,10 @@ public function build() { /** * {@inheritdoc} */ - public function buildConfigurationForm(array $form, array &$form_state) { - $form = parent::buildConfigurationForm($form, $form_state); - - // Remove the required cache contexts from the list of contexts a user can - // choose to modify by: they must always be applied. - $context_labels = array(); - foreach ($this->getRequiredCacheContexts() as $context) { - $context_labels[] = $form['cache']['contexts']['#options'][$context]; - unset($form['cache']['contexts']['#options'][$context]); - } - $required_context_list = implode(', ', $context_labels); - $form['cache']['contexts']['#description'] .= ' ' . t('This block is always varied by the following contexts: %required-context-list.', array('%required-context-list' => $required_context_list)); - - return $form; - } - - /** - * {@inheritdoc} - */ - public function getCacheKeys() { - // Return the required cache contexts, merged with the user-configured cache - // contexts, if any. - return array_merge($this->getRequiredCacheContexts(), parent::getCacheKeys()); - } - - /** - * Returns the cache contexts required for this block. - * - * Two cache contexts are required: cache by URL and by user's roles. - * - * @return array - * The required cache contexts IDs. - */ protected function getRequiredCacheContexts() { + // The "Book navigation" block must be cached per URL and per role: the + // "active" menu link may differ per URL and different roles may have access + // to different menu links. return array('cache_context.url', 'cache_context.user.roles'); } diff --git a/core/modules/search/lib/Drupal/search/Form/SearchBlockForm.php b/core/modules/search/lib/Drupal/search/Form/SearchBlockForm.php index ad96735..0635eb0 100644 --- a/core/modules/search/lib/Drupal/search/Form/SearchBlockForm.php +++ b/core/modules/search/lib/Drupal/search/Form/SearchBlockForm.php @@ -103,4 +103,13 @@ public function submitForm(array &$form, array &$form_state) { } } + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + // This is a block containing a simple form without state, which is safe to + // cache forever. + return array('cache' => array('max_age' => \Drupal\Core\Cache\Cache::PERMANENT)); + } + } diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php index 89a859d..c594b98 100644 --- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php +++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php @@ -120,23 +120,21 @@ public function build() { /** * {@inheritdoc} */ - public function buildConfigurationForm(array $form, array &$form_state) { - $form = parent::buildConfigurationForm($form, $form_state); - - // The help block is never cacheable, because it is path-specific. - $form['cache']['#disabled'] = TRUE; - $form['cache']['#description'] = t('This block is never cacheable, it is not configurable.'); - $form['cache']['max_age']['#value'] = 0; - - return $form; + public function defaultConfiguration() { + // Modify the default max age for the System Help block: help text is static + // for a given URL, except when a module is updated, in which case + // update.php must be run, which clears all caches. Thus it's safe to cache + // the output for this block forever on a per-URL basis. + return array('cache' => array('max_age' => \Drupal\Core\Cache\Cache::PERMANENT)); } /** * {@inheritdoc} */ - public function isCacheable() { - // The help block is never cacheable, because it is path-specific. - return FALSE; + protected function getRequiredCacheContexts() { + // The "System Help" block must be cached per URL: help is defined for a + // given path, and does not come with any access restrictions. + return array('cache_context.url'); } } diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php index c3b5463..b6d1316 100644 --- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php +++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php @@ -48,25 +48,6 @@ public function defaultConfiguration() { /** * {@inheritdoc} */ - public function buildConfigurationForm(array $form, array &$form_state) { - $form = parent::buildConfigurationForm($form, $form_state); - - // Remove the required cache contexts from the list of contexts a user can - // choose to modify by: they must always be applied. - $context_labels = array(); - foreach ($this->getRequiredCacheContexts() as $context) { - $context_labels[] = $form['cache']['contexts']['#options'][$context]; - unset($form['cache']['contexts']['#options'][$context]); - } - $required_context_list = implode(', ', $context_labels); - $form['cache']['contexts']['#description'] .= ' ' . t('This block is always varied by the following contexts: %required-context-list.', array('%required-context-list' => $required_context_list)); - - return $form; - } - - /** - * {@inheritdoc} - */ public function getCacheKeys() { // Return the required cache contexts, merged with the user-configured cache // contexts, if any. @@ -86,14 +67,12 @@ public function getCacheTags() { } /** - * Returns the cache contexts required for this block. - * - * Two cache contexts are required: cache by URL and by user's roles. - * - * @return array - * The required cache contexts IDs. + * {@inheritdoc} */ protected function getRequiredCacheContexts() { + // Menu blocks must be cached per URL and per role: the "active" menu link + // may differ per URL and different roles may have access to different menu + // links. return array('cache_context.url', 'cache_context.user.roles'); } diff --git a/core/modules/user/lib/Drupal/user/EventSubscriber/UserLoginBlockConfigChangeSubscriber.php b/core/modules/user/lib/Drupal/user/EventSubscriber/UserLoginBlockConfigChangeSubscriber.php new file mode 100644 index 0000000..d307dee --- /dev/null +++ b/core/modules/user/lib/Drupal/user/EventSubscriber/UserLoginBlockConfigChangeSubscriber.php @@ -0,0 +1,40 @@ +getConfig()->getName() === 'user.settings' && $event->isChanged('register')) { + Cache::invalidateTags(array('block_plugin' => array('user_login_block'))); + } + } + + /** + * {@inheritdoc} + */ + static function getSubscribedEvents() { + $events[ConfigEvents::SAVE][] = array('onConfigSave', 0); + return $events; + } + +} diff --git a/core/modules/user/lib/Drupal/user/Plugin/Block/UserLoginBlock.php b/core/modules/user/lib/Drupal/user/Plugin/Block/UserLoginBlock.php index c087889..19266ab 100644 --- a/core/modules/user/lib/Drupal/user/Plugin/Block/UserLoginBlock.php +++ b/core/modules/user/lib/Drupal/user/Plugin/Block/UserLoginBlock.php @@ -64,4 +64,13 @@ public function build() { ); } + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + // This is a block containing a simple form without state, which is safe to + // cache forever. + return array('cache' => array('max_age' => \Drupal\Core\Cache\Cache::PERMANENT)); + } + } diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml index 7f73ccc..45af7f1 100644 --- a/core/modules/user/user.services.yml +++ b/core/modules/user/user.services.yml @@ -35,6 +35,10 @@ services: class: Drupal\user\EventSubscriber\MaintenanceModeSubscriber tags: - { name: event_subscriber } + user_login_block_config_change_subscriber: + class: Drupal\user\EventSubscriber\UserLoginBlockConfigChangeSubscriber + tags: + - { name: event_subscriber } theme.negotiator.admin_theme: class: Drupal\user\Theme\AdminNegotiator arguments: ['@current_user', '@config.factory', '@entity.manager']