Unverified Commit 082c37d7 authored by Alex Pott's avatar Alex Pott
Browse files

task: #941970 Rebuild router only when something related to routing changes

By: dawehner
By: andrewbelcher
By: damiankloip
By: berdir
By: mortona2k
By: mpdonadio
By: lendude
By: joelpittet
By: alexpott
By: xjm
By: catch
By: dave reid
By: claudiu.cristea
By: nicxvan
By: graber
By: oily
By: quietone
By: godotislate
(cherry picked from commit 99c79fcd)
parent a776fda6
Loading
Loading
Loading
Loading
+21 −1
Changes for core/modules/rest/src/Plugin/views/style/Serializer.php: 21 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -7,7 +7,10 @@
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\views\Attribute\ViewsStyle;
use Drupal\views\Plugin\views\display\DisplayPluginInterface;
use Drupal\views\Plugin\views\style\StylePluginBase;
use Drupal\views\PostSaveProcess;
use Drupal\views\PostSaveViewInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Serializer\SerializerInterface;

@@ -22,7 +25,7 @@
  help: new TranslatableMarkup("Serializes views row data using the Serializer component."),
  display_types: ["data"],
)]
class Serializer extends StylePluginBase implements CacheableDependencyInterface {
class Serializer extends StylePluginBase implements CacheableDependencyInterface, PostSaveViewInterface {

  /**
   * {@inheritdoc}
@@ -143,6 +146,23 @@ public function render() {
    return $this->serializer->serialize($rows, $content_type, ['views_style_plugin' => $this]);
  }

  /**
   * {@inheritdoc}
   */
  public function postSaveView(PostSaveProcess $postSaveProcess, ?DisplayPluginInterface $original_display = NULL): void {
    if ($postSaveProcess->needsRouterRebuild()) {
      return;
    }
    // We need a router rebuild if the available formats have changed because
    // the formats are stored on the route.
    $original_style = $original_display?->getOption('style') ?? [];
    $original_formats = $original_style['options']['formats'] ?? [];

    if ($original_formats != $this->getFormats()) {
      $postSaveProcess->setRouterRebuild();
    }
  }

  /**
   * Gets a list of all available formats that can be requested.
   *
+45 −6
Changes for core/modules/views/src/Entity/View.php: 45 added lines, 6 removed lines.
Original line number Diff line number Diff line
@@ -11,6 +11,8 @@
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\views\Plugin\DependentWithRemovalPluginInterface;
use Drupal\views\PostSaveProcess;
use Drupal\views\PostSaveViewInterface;
use Drupal\views\Views;
use Drupal\views\ViewEntityInterface;

@@ -348,13 +350,50 @@ protected function addCacheMetadata() {
  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
    parent::postSave($storage, $update);

    // @todo Remove if views implements a view_builder controller.
    views_invalidate_cache();
    $this->invalidateCaches();
    Views::invalidateCache();
    // Track for each display, handler and plugin whether action was taken in
    // the postsave callback.
    $postSaveProcess = new PostSaveProcess();

    // Rebuild the router if this is a new view, or its status changed.
    if (!$this->getOriginal() || ($this->status() != $this->getOriginal()->status())) {
    $executable = $this->getExecutable();
    $original_executable = NULL;
    if ($this->getOriginal()) {
      $original_executable = $this->getOriginal()->getExecutable();
      $original_executable->initDisplay();
    }
    $executable->initDisplay();
    foreach ($executable->displayHandlers as $display_id => $display_handler) {
      $original_display_handler = NULL;
      if ($original_executable && $original_executable->displayHandlers->has($display_id)) {
        $original_executable->setDisplay($display_id);
        $original_display_handler = $original_executable->display_handler;
      }
      if ($display_handler instanceof PostSaveViewInterface) {
        $display_handler->postSaveView($postSaveProcess, $original_display_handler);
      }
      foreach (\array_keys(Views::getHandlerTypes()) as $handler_type) {
        foreach ($display_handler->getHandlers($handler_type) as $handler) {
          if ($handler instanceof PostSaveViewInterface) {
            $handler->postSaveView($postSaveProcess, $original_display_handler);
          }
        }
      }
      foreach (Views::getPluginTypes('plugin') as $plugin_type) {
        $plugin = $display_handler->getPlugin($plugin_type);
        if (!empty($plugin) && $plugin instanceof PostSaveViewInterface) {
          $plugin->postSaveView($postSaveProcess, $original_display_handler);
        }
      }
    }

    if ($postSaveProcess->needsRouterRebuild()) {
      // Set the router as needing to be rebuilt.
      \Drupal::service('router.builder')->setRebuildNeeded();
      // Reset the RouteSubscriber from views.
      \Drupal::service('views.route_subscriber')->reset();
    }
    foreach ($postSaveProcess->getDiscoveriesToClear() as $discovery) {
      $discovery->clearCachedDefinitions();
    }
  }

@@ -426,7 +465,7 @@ public static function postDelete(EntityStorageInterface $storage, array $entiti
      $tempstore->delete($entity->id());
    }

    views_invalidate_cache();
    Views::invalidateCache();
  }

  /**
+12 −1
Changes for core/modules/views/src/Plugin/views/display/Block.php: 12 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -11,6 +11,8 @@
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Attribute\ViewsDisplay;
use Drupal\views\Plugin\Block\ViewsBlock;
use Drupal\views\PostSaveProcess;
use Drupal\views\PostSaveViewInterface;

/**
 * The plugin that handles a block.
@@ -30,7 +32,7 @@
  uses_hook_block: TRUE,
  contextual_links_locations: ["block"]
)]
class Block extends DisplayPluginBase {
class Block extends DisplayPluginBase implements PostSaveViewInterface {

  /**
   * Whether the display allows attachments.
@@ -385,4 +387,13 @@ public function remove() {
    }
  }

  /**
   * {@inheritdoc}
   */
  public function postSaveView(PostSaveProcess $postSaveProcess, ?DisplayPluginInterface $original_display = NULL): void {
    if ($this->blockManager instanceof CachedDiscoveryInterface) {
      $postSaveProcess->addDiscoveryToClear($this->blockManager);
    }
  }

}
+7 −0
Changes for core/modules/views/src/Plugin/views/display/Page.php: 7 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -608,4 +608,11 @@ public function calculateDependencies() {
    return $dependencies;
  }

  /**
   * {@inheritdoc}
   */
  protected function getRouteAffectingOptions(): array {
    return [...parent::getRouteAffectingOptions(), 'menu', 'tab_options'];
  }

}
+48 −2
Changes for core/modules/views/src/Plugin/views/display/PathPluginBase.php: 48 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -6,10 +6,12 @@
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Routing\RouteCompiler;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Url;
use Drupal\views\PostSaveProcess;
use Drupal\views\PostSaveViewInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Route;
@@ -20,7 +22,7 @@
 *
 * @see \Drupal\views\EventSubscriber\RouteSubscriber
 */
abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouterInterface, DisplayMenuInterface {
abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouterInterface, DisplayMenuInterface, PostSaveViewInterface {

  /**
   * The route provider.
@@ -560,6 +562,50 @@ public function remove() {
    foreach ($menu_links as $menu_link_id => $menu_link) {
      $menu_link_manager->removeDefinition("views_view:$menu_link_id");
    }

    // Set the router as needing to be rebuilt.
    \Drupal::service('router.builder')->setRebuildNeeded();
    // Reset the RouteSubscriber from views.
    \Drupal::service('views.route_subscriber')->reset();
  }

  /**
   * {@inheritdoc}
   */
  public function postSaveView(PostSaveProcess $postSaveProcess, ?DisplayPluginInterface $original_display = NULL): void {
    if ($postSaveProcess->needsRouterRebuild()) {
      return;
    }

    // An empty original display means a new view, we need a router rebuild.
    if (!$original_display) {
      $postSaveProcess->setRouterRebuild();
      return;
    }

    // Rebuild the router when the enclosing view status has changed.
    if ($this->view->storage->status() != $original_display->view->storage->status()) {
      $postSaveProcess->setRouterRebuild();
      return;
    }

    // Rebuild if at least one of the route-affecting options has changed.
    foreach ($this->getRouteAffectingOptions() as $option) {
      if ($this->getOption($option) != $original_display->getOption($option)) {
        $postSaveProcess->setRouterRebuild();
        return;
      }
    }
  }

  /**
   * Returns the display options whom update could affect the route on rebuild.
   *
   * @return string[]
   *   Display options.
   */
  protected function getRouteAffectingOptions(): array {
    return ['path', 'route_name', 'arguments', 'access', 'enabled'];
  }

}
Loading