From 35ddee690b3fc834c0adc52af7e713ff7ac8c5bb Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Tue, 26 Mar 2019 11:22:52 +0000
Subject: [PATCH] Issue #3029625 by tim.plunkett: Do not throw an exception
 when a context is missing while applying context mapping to a plugin if that
 context was previously set

(cherry picked from commit 8c90cbfdf787249213c9b6766cd5f5d7e5cad8b6)
---
 .../Core/Plugin/Context/ContextHandler.php    |  4 ++++
 .../Core/Plugin/ContextHandlerTest.php        | 19 +++++++++++++++++++
 .../Tests/Core/Plugin/ContextHandlerTest.php  | 11 +++++++----
 3 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php b/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php
index eb8b628276fb..c4a41b8e917a 100644
--- a/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php
+++ b/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php
@@ -111,6 +111,10 @@ public function applyContextMapping(ContextAwarePluginInterface $plugin, $contex
           $missing_value[] = $plugin_context_id;
         }
       }
+      elseif (($context = $plugin->getContext($context_id)) && $context->hasContextValue()) {
+        // Ignore mappings if the plugin has a value for a missing context.
+        unset($mappings[$plugin_context_id]);
+      }
       elseif ($plugin_context_definition->isRequired()) {
         // Collect required contexts that are missing.
         $missing_value[] = $plugin_context_id;
diff --git a/core/tests/Drupal/KernelTests/Core/Plugin/ContextHandlerTest.php b/core/tests/Drupal/KernelTests/Core/Plugin/ContextHandlerTest.php
index 09ab7af9fe94..a3a43d871c18 100644
--- a/core/tests/Drupal/KernelTests/Core/Plugin/ContextHandlerTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Plugin/ContextHandlerTest.php
@@ -42,6 +42,25 @@ public function testApplyContextMapping() {
     $this->assertSame($context, $result);
   }
 
+  /**
+   * @covers ::applyContextMapping
+   */
+  public function testApplyContextMappingAlreadyApplied() {
+    $entity = EntityTest::create([]);
+    $context_definition = EntityContextDefinition::fromEntity($entity);
+    $context = EntityContext::fromEntity($entity);
+
+    $definition = ['context_definitions' => ['a_context_id' => $context_definition]];
+    $plugin = new TestContextAwarePlugin([], 'test_plugin_id', $definition);
+    $plugin->setContext('a_context_id', $context);
+    (new ContextHandler())->applyContextMapping($plugin, []);
+
+    $result = $plugin->getContext('a_context_id');
+
+    $this->assertInstanceOf(EntityContext::class, $result);
+    $this->assertSame($context, $result);
+  }
+
 }
 
 /**
diff --git a/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php b/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php
index 3cf6a1d45d34..05935e11fe8b 100644
--- a/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php
+++ b/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php
@@ -18,6 +18,7 @@
 use Drupal\Core\DependencyInjection\ClassResolverInterface;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\Context\Context;
 use Drupal\Core\Plugin\Context\ContextDefinition;
 use Drupal\Core\Plugin\Context\ContextHandler;
 use Drupal\Core\Plugin\ContextAwarePluginInterface;
@@ -378,8 +379,9 @@ public function testApplyContextMappingMissingRequired() {
       ->method('setContext');
 
     // No context, so no cacheability metadata can be passed along.
-    $plugin->expects($this->never())
-      ->method('getContext');
+    $plugin->expects($this->once())
+      ->method('getContext')
+      ->willReturn(new Context($context_definition));
 
     $this->setExpectedException(MissingValueContextException::class, 'Required contexts without a value: hit');
     $this->contextHandler->applyContextMapping($plugin, $contexts);
@@ -413,8 +415,9 @@ public function testApplyContextMappingMissingNotRequired() {
       ->method('setContext');
 
     // No context, so no cacheability metadata can be passed along.
-    $plugin->expects($this->never())
-      ->method('getContext');
+    $plugin->expects($this->once())
+      ->method('getContext')
+      ->willReturn(new Context($context_definition));
 
     $this->contextHandler->applyContextMapping($plugin, $contexts);
   }
-- 
GitLab