ContextHandlerTest.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. <?php
  2. /**
  3. * @file
  4. * Contains \Drupal\Tests\Core\Plugin\ContextHandlerTest.
  5. */
  6. namespace Drupal\Tests\Core\Plugin;
  7. use Drupal\Component\Plugin\ConfigurableInterface;
  8. use Drupal\Component\Plugin\DependentPluginInterface;
  9. use Drupal\Component\Plugin\Definition\ContextAwarePluginDefinitionInterface;
  10. use Drupal\Component\Plugin\Definition\ContextAwarePluginDefinitionTrait;
  11. use Drupal\Component\Plugin\Definition\PluginDefinition;
  12. use Drupal\Component\Plugin\Exception\ContextException;
  13. use Drupal\Component\Plugin\Exception\MissingValueContextException;
  14. use Drupal\Core\Cache\NullBackend;
  15. use Drupal\Core\DependencyInjection\ClassResolverInterface;
  16. use Drupal\Core\DependencyInjection\ContainerBuilder;
  17. use Drupal\Core\Extension\ModuleHandlerInterface;
  18. use Drupal\Core\Plugin\Context\ContextDefinition;
  19. use Drupal\Core\Plugin\Context\ContextHandler;
  20. use Drupal\Core\Plugin\ContextAwarePluginInterface;
  21. use Drupal\Core\TypedData\TypedDataManager;
  22. use Drupal\Core\Validation\ConstraintManager;
  23. use Drupal\Tests\UnitTestCase;
  24. use Prophecy\Argument;
  25. /**
  26. * @coversDefaultClass \Drupal\Core\Plugin\Context\ContextHandler
  27. * @group Plugin
  28. */
  29. class ContextHandlerTest extends UnitTestCase {
  30. /**
  31. * The context handler.
  32. *
  33. * @var \Drupal\Core\Plugin\Context\ContextHandler
  34. */
  35. protected $contextHandler;
  36. /**
  37. * {@inheritdoc}
  38. */
  39. protected function setUp() {
  40. parent::setUp();
  41. $this->contextHandler = new ContextHandler();
  42. $namespaces = new \ArrayObject([
  43. 'Drupal\\Core\\TypedData' => $this->root . '/core/lib/Drupal/Core/TypedData',
  44. 'Drupal\\Core\\Validation' => $this->root . '/core/lib/Drupal/Core/Validation',
  45. ]);
  46. $cache_backend = new NullBackend('cache');
  47. $module_handler = $this->prophesize(ModuleHandlerInterface::class);
  48. $class_resolver = $this->prophesize(ClassResolverInterface::class);
  49. $class_resolver->getInstanceFromDefinition(Argument::type('string'))->will(function ($arguments) {
  50. $class_name = $arguments[0];
  51. return new $class_name();
  52. });
  53. $type_data_manager = new TypedDataManager($namespaces, $cache_backend, $module_handler->reveal(), $class_resolver->reveal());
  54. $type_data_manager->setValidationConstraintManager(
  55. new ConstraintManager($namespaces, $cache_backend, $module_handler->reveal())
  56. );
  57. $container = new ContainerBuilder();
  58. $container->set('typed_data_manager', $type_data_manager);
  59. \Drupal::setContainer($container);
  60. }
  61. /**
  62. * @covers ::checkRequirements
  63. *
  64. * @dataProvider providerTestCheckRequirements
  65. */
  66. public function testCheckRequirements($contexts, $requirements, $expected) {
  67. $this->assertSame($expected, $this->contextHandler->checkRequirements($contexts, $requirements));
  68. }
  69. /**
  70. * Provides data for testCheckRequirements().
  71. */
  72. public function providerTestCheckRequirements() {
  73. $requirement_optional = new ContextDefinition();
  74. $requirement_optional->setRequired(FALSE);
  75. $requirement_any = new ContextDefinition();
  76. $requirement_any->setRequired(TRUE);
  77. $context_any = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  78. $context_any->expects($this->atLeastOnce())
  79. ->method('getContextDefinition')
  80. ->will($this->returnValue(new ContextDefinition('any')));
  81. $requirement_specific = new ContextDefinition('string');
  82. $requirement_specific->setConstraints(['Blank' => []]);
  83. $context_constraint_mismatch = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  84. $context_constraint_mismatch->expects($this->atLeastOnce())
  85. ->method('getContextDefinition')
  86. ->will($this->returnValue(new ContextDefinition('foo')));
  87. $context_datatype_mismatch = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  88. $context_datatype_mismatch->expects($this->atLeastOnce())
  89. ->method('getContextDefinition')
  90. ->will($this->returnValue(new ContextDefinition('fuzzy')));
  91. $context_definition_specific = new ContextDefinition('string');
  92. $context_definition_specific->setConstraints(['Blank' => []]);
  93. $context_specific = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  94. $context_specific->expects($this->atLeastOnce())
  95. ->method('getContextDefinition')
  96. ->will($this->returnValue($context_definition_specific));
  97. $data = [];
  98. $data[] = [[], [], TRUE];
  99. $data[] = [[], [$requirement_any], FALSE];
  100. $data[] = [[], [$requirement_optional], TRUE];
  101. $data[] = [[], [$requirement_any, $requirement_optional], FALSE];
  102. $data[] = [[$context_any], [$requirement_any], TRUE];
  103. $data[] = [[$context_constraint_mismatch], [$requirement_specific], FALSE];
  104. $data[] = [[$context_datatype_mismatch], [$requirement_specific], FALSE];
  105. $data[] = [[$context_specific], [$requirement_specific], TRUE];
  106. return $data;
  107. }
  108. /**
  109. * @covers ::getMatchingContexts
  110. *
  111. * @dataProvider providerTestGetMatchingContexts
  112. */
  113. public function testGetMatchingContexts($contexts, $requirement, $expected = NULL) {
  114. if (is_null($expected)) {
  115. $expected = $contexts;
  116. }
  117. $this->assertSame($expected, $this->contextHandler->getMatchingContexts($contexts, $requirement));
  118. }
  119. /**
  120. * Provides data for testGetMatchingContexts().
  121. */
  122. public function providerTestGetMatchingContexts() {
  123. $requirement_any = new ContextDefinition();
  124. $requirement_specific = new ContextDefinition('string');
  125. $requirement_specific->setConstraints(['Blank' => []]);
  126. $context_any = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  127. $context_any->expects($this->atLeastOnce())
  128. ->method('getContextDefinition')
  129. ->will($this->returnValue(new ContextDefinition('any')));
  130. $context_constraint_mismatch = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  131. $context_constraint_mismatch->expects($this->atLeastOnce())
  132. ->method('getContextDefinition')
  133. ->will($this->returnValue(new ContextDefinition('foo')));
  134. $context_datatype_mismatch = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  135. $context_datatype_mismatch->expects($this->atLeastOnce())
  136. ->method('getContextDefinition')
  137. ->will($this->returnValue(new ContextDefinition('fuzzy')));
  138. $context_definition_specific = new ContextDefinition('string');
  139. $context_definition_specific->setConstraints(['Blank' => []]);
  140. $context_specific = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  141. $context_specific->expects($this->atLeastOnce())
  142. ->method('getContextDefinition')
  143. ->will($this->returnValue($context_definition_specific));
  144. $data = [];
  145. // No context will return no valid contexts.
  146. $data[] = [[], $requirement_any];
  147. // A context with a generic matching requirement is valid.
  148. $data[] = [[$context_any], $requirement_any];
  149. // A context with a specific matching requirement is valid.
  150. $data[] = [[$context_specific], $requirement_specific];
  151. // A context with a mismatched constraint is invalid.
  152. $data[] = [[$context_constraint_mismatch], $requirement_specific, []];
  153. // A context with a mismatched datatype is invalid.
  154. $data[] = [[$context_datatype_mismatch], $requirement_specific, []];
  155. return $data;
  156. }
  157. /**
  158. * @covers ::filterPluginDefinitionsByContexts
  159. *
  160. * @dataProvider providerTestFilterPluginDefinitionsByContexts
  161. */
  162. public function testFilterPluginDefinitionsByContexts($has_context, $definitions, $expected) {
  163. if ($has_context) {
  164. $context = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  165. $expected_context_definition = (new ContextDefinition('string'))->setConstraints(['Blank' => []]);
  166. $context->expects($this->atLeastOnce())
  167. ->method('getContextDefinition')
  168. ->will($this->returnValue($expected_context_definition));
  169. $contexts = [$context];
  170. }
  171. else {
  172. $contexts = [];
  173. }
  174. $this->assertSame($expected, $this->contextHandler->filterPluginDefinitionsByContexts($contexts, $definitions));
  175. }
  176. /**
  177. * Provides data for testFilterPluginDefinitionsByContexts().
  178. */
  179. public function providerTestFilterPluginDefinitionsByContexts() {
  180. $data = [];
  181. $plugins = [];
  182. // No context and no plugins, no plugins available.
  183. $data[] = [FALSE, $plugins, []];
  184. $plugins = [
  185. 'expected_array_plugin' => [],
  186. 'expected_object_plugin' => new ContextAwarePluginDefinition(),
  187. ];
  188. // No context, all plugins available.
  189. $data[] = [FALSE, $plugins, $plugins];
  190. $plugins = [
  191. 'expected_array_plugin' => ['context_definitions' => []],
  192. 'expected_object_plugin' => new ContextAwarePluginDefinition(),
  193. ];
  194. // No context, all plugins available.
  195. $data[] = [FALSE, $plugins, $plugins];
  196. $plugins = [
  197. 'expected_array_plugin' => [
  198. 'context_definitions' => ['context1' => new ContextDefinition('string')],
  199. ],
  200. 'expected_object_plugin' => (new ContextAwarePluginDefinition())
  201. ->addContextDefinition('context1', new ContextDefinition('string')),
  202. ];
  203. // Missing context, no plugins available.
  204. $data[] = [FALSE, $plugins, []];
  205. // Satisfied context, all plugins available.
  206. $data[] = [TRUE, $plugins, $plugins];
  207. $mismatched_context_definition = (new ContextDefinition('expected_data_type'))->setConstraints(['mismatched_constraint_name' => 'mismatched_constraint_value']);
  208. $plugins = [
  209. 'expected_array_plugin' => [
  210. 'context_definitions' => ['context1' => $mismatched_context_definition],
  211. ],
  212. 'expected_object_plugin' => (new ContextAwarePluginDefinition())
  213. ->addContextDefinition('context1', $mismatched_context_definition),
  214. ];
  215. // Mismatched constraints, no plugins available.
  216. $data[] = [TRUE, $plugins, []];
  217. $optional_mismatched_context_definition = clone $mismatched_context_definition;
  218. $optional_mismatched_context_definition->setRequired(FALSE);
  219. $plugins = [
  220. 'expected_array_plugin' => [
  221. 'context_definitions' => ['context1' => $optional_mismatched_context_definition],
  222. ],
  223. 'expected_object_plugin' => (new ContextAwarePluginDefinition())
  224. ->addContextDefinition('context1', $optional_mismatched_context_definition),
  225. ];
  226. // Optional mismatched constraint, all plugins available.
  227. $data[] = [FALSE, $plugins, $plugins];
  228. $expected_context_definition = (new ContextDefinition('string'))->setConstraints(['Blank' => []]);
  229. $plugins = [
  230. 'expected_array_plugin' => [
  231. 'context_definitions' => ['context1' => $expected_context_definition],
  232. ],
  233. 'expected_object_plugin' => (new ContextAwarePluginDefinition())
  234. ->addContextDefinition('context1', $expected_context_definition),
  235. ];
  236. // Satisfied context with constraint, all plugins available.
  237. $data[] = [TRUE, $plugins, $plugins];
  238. $optional_expected_context_definition = clone $expected_context_definition;
  239. $optional_expected_context_definition->setRequired(FALSE);
  240. $plugins = [
  241. 'expected_array_plugin' => [
  242. 'context_definitions' => ['context1' => $optional_expected_context_definition],
  243. ],
  244. 'expected_object_plugin' => (new ContextAwarePluginDefinition())
  245. ->addContextDefinition('context1', $optional_expected_context_definition),
  246. ];
  247. // Optional unsatisfied context, all plugins available.
  248. $data[] = [FALSE, $plugins, $plugins];
  249. $unexpected_context_definition = (new ContextDefinition('unexpected_data_type'))->setConstraints(['mismatched_constraint_name' => 'mismatched_constraint_value']);
  250. $plugins = [
  251. 'unexpected_array_plugin' => [
  252. 'context_definitions' => ['context1' => $unexpected_context_definition],
  253. ],
  254. 'expected_array_plugin' => [
  255. 'context_definitions' => ['context2' => new ContextDefinition('string')],
  256. ],
  257. 'unexpected_object_plugin' => (new ContextAwarePluginDefinition())
  258. ->addContextDefinition('context1', $unexpected_context_definition),
  259. 'expected_object_plugin' => (new ContextAwarePluginDefinition())
  260. ->addContextDefinition('context2', new ContextDefinition('string')),
  261. ];
  262. // Context only satisfies two plugins.
  263. $data[] = [
  264. TRUE,
  265. $plugins,
  266. [
  267. 'expected_array_plugin' => $plugins['expected_array_plugin'],
  268. 'expected_object_plugin' => $plugins['expected_object_plugin'],
  269. ],
  270. ];
  271. return $data;
  272. }
  273. /**
  274. * @covers ::applyContextMapping
  275. */
  276. public function testApplyContextMapping() {
  277. $context_hit = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  278. $context_hit->expects($this->atLeastOnce())
  279. ->method('hasContextValue')
  280. ->willReturn(TRUE);
  281. $context_miss = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  282. $contexts = [
  283. 'hit' => $context_hit,
  284. 'miss' => $context_miss,
  285. ];
  286. $context_definition = $this->createMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
  287. $plugin = $this->createMock('Drupal\Core\Plugin\ContextAwarePluginInterface');
  288. $plugin->expects($this->once())
  289. ->method('getContextMapping')
  290. ->willReturn([]);
  291. $plugin->expects($this->once())
  292. ->method('getContextDefinitions')
  293. ->will($this->returnValue(['hit' => $context_definition]));
  294. $plugin->expects($this->once())
  295. ->method('setContext')
  296. ->with('hit', $context_hit);
  297. // Make sure that the cacheability metadata is passed to the plugin context.
  298. $plugin_context = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  299. $plugin_context->expects($this->once())
  300. ->method('addCacheableDependency')
  301. ->with($context_hit);
  302. $plugin->expects($this->once())
  303. ->method('getContext')
  304. ->with('hit')
  305. ->willReturn($plugin_context);
  306. $this->contextHandler->applyContextMapping($plugin, $contexts);
  307. }
  308. /**
  309. * @covers ::applyContextMapping
  310. */
  311. public function testApplyContextMappingMissingRequired() {
  312. $context = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  313. $context->expects($this->never())
  314. ->method('getContextValue');
  315. $contexts = [
  316. 'name' => $context,
  317. ];
  318. $context_definition = $this->createMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
  319. $context_definition->expects($this->atLeastOnce())
  320. ->method('isRequired')
  321. ->willReturn(TRUE);
  322. $plugin = $this->createMock('Drupal\Tests\Core\Plugin\TestConfigurableContextAwarePluginInterface');
  323. $plugin->expects($this->once())
  324. ->method('getContextMapping')
  325. ->willReturn([]);
  326. $plugin->expects($this->once())
  327. ->method('getContextDefinitions')
  328. ->will($this->returnValue(['hit' => $context_definition]));
  329. $plugin->expects($this->never())
  330. ->method('setContext');
  331. // No context, so no cacheability metadata can be passed along.
  332. $plugin->expects($this->any())
  333. ->method('getContext')
  334. ->willThrowException(new ContextException());
  335. $this->expectException(MissingValueContextException::class);
  336. $this->expectExceptionMessage('Required contexts without a value: hit');
  337. $this->contextHandler->applyContextMapping($plugin, $contexts);
  338. }
  339. /**
  340. * @covers ::applyContextMapping
  341. */
  342. public function testApplyContextMappingMissingNotRequired() {
  343. $context = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  344. $context->expects($this->never())
  345. ->method('getContextValue');
  346. $contexts = [
  347. 'name' => $context,
  348. ];
  349. $context_definition = $this->createMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
  350. $context_definition->expects($this->atLeastOnce())
  351. ->method('isRequired')
  352. ->willReturn(FALSE);
  353. $plugin = $this->createMock('Drupal\Tests\Core\Plugin\TestConfigurableContextAwarePluginInterface');
  354. $plugin->expects($this->once())
  355. ->method('getContextMapping')
  356. ->willReturn(['optional' => 'missing']);
  357. $plugin->expects($this->once())
  358. ->method('getContextDefinitions')
  359. ->will($this->returnValue(['optional' => $context_definition]));
  360. $plugin->expects($this->never())
  361. ->method('setContext');
  362. // No context, so no cacheability metadata can be passed along.
  363. $plugin->expects($this->any())
  364. ->method('getContext')
  365. ->willThrowException(new ContextException());
  366. $this->contextHandler->applyContextMapping($plugin, $contexts);
  367. }
  368. /**
  369. * @covers ::applyContextMapping
  370. */
  371. public function testApplyContextMappingNoValueRequired() {
  372. $context = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  373. $context->expects($this->never())
  374. ->method('getContextValue');
  375. $context->expects($this->atLeastOnce())
  376. ->method('hasContextValue')
  377. ->willReturn(FALSE);
  378. $contexts = [
  379. 'hit' => $context,
  380. ];
  381. $context_definition = $this->createMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
  382. $context_definition->expects($this->atLeastOnce())
  383. ->method('isRequired')
  384. ->willReturn(TRUE);
  385. $plugin = $this->createMock('Drupal\Tests\Core\Plugin\TestConfigurableContextAwarePluginInterface');
  386. $plugin->expects($this->once())
  387. ->method('getContextMapping')
  388. ->willReturn([]);
  389. $plugin->expects($this->once())
  390. ->method('getContextDefinitions')
  391. ->will($this->returnValue(['hit' => $context_definition]));
  392. $plugin->expects($this->never())
  393. ->method('setContext');
  394. $this->expectException(MissingValueContextException::class);
  395. $this->expectExceptionMessage('Required contexts without a value: hit');
  396. $this->contextHandler->applyContextMapping($plugin, $contexts);
  397. }
  398. /**
  399. * @covers ::applyContextMapping
  400. */
  401. public function testApplyContextMappingNoValueNonRequired() {
  402. $context = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  403. $context->expects($this->never())
  404. ->method('getContextValue');
  405. $context->expects($this->atLeastOnce())
  406. ->method('hasContextValue')
  407. ->willReturn(FALSE);
  408. $contexts = [
  409. 'hit' => $context,
  410. ];
  411. $context_definition = $this->createMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
  412. $context_definition->expects($this->atLeastOnce())
  413. ->method('isRequired')
  414. ->willReturn(FALSE);
  415. $plugin = $this->createMock('Drupal\Tests\Core\Plugin\TestConfigurableContextAwarePluginInterface');
  416. $plugin->expects($this->once())
  417. ->method('getContextMapping')
  418. ->willReturn([]);
  419. $plugin->expects($this->once())
  420. ->method('getContextDefinitions')
  421. ->will($this->returnValue(['hit' => $context_definition]));
  422. $plugin->expects($this->never())
  423. ->method('setContext');
  424. $this->contextHandler->applyContextMapping($plugin, $contexts);
  425. }
  426. /**
  427. * @covers ::applyContextMapping
  428. */
  429. public function testApplyContextMappingConfigurableAssigned() {
  430. $context = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  431. $context->expects($this->atLeastOnce())
  432. ->method('hasContextValue')
  433. ->willReturn(TRUE);
  434. $contexts = [
  435. 'name' => $context,
  436. ];
  437. $context_definition = $this->createMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
  438. $plugin = $this->createMock('Drupal\Tests\Core\Plugin\TestConfigurableContextAwarePluginInterface');
  439. $plugin->expects($this->once())
  440. ->method('getContextMapping')
  441. ->willReturn([]);
  442. $plugin->expects($this->once())
  443. ->method('getContextDefinitions')
  444. ->will($this->returnValue(['hit' => $context_definition]));
  445. $plugin->expects($this->once())
  446. ->method('setContext')
  447. ->with('hit', $context);
  448. // Make sure that the cacheability metadata is passed to the plugin context.
  449. $plugin_context = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  450. $plugin_context->expects($this->once())
  451. ->method('addCacheableDependency')
  452. ->with($context);
  453. $plugin->expects($this->once())
  454. ->method('getContext')
  455. ->with('hit')
  456. ->willReturn($plugin_context);
  457. $this->contextHandler->applyContextMapping($plugin, $contexts, ['hit' => 'name']);
  458. }
  459. /**
  460. * @covers ::applyContextMapping
  461. */
  462. public function testApplyContextMappingConfigurableAssignedMiss() {
  463. $context = $this->createMock('Drupal\Core\Plugin\Context\ContextInterface');
  464. $context->expects($this->never())
  465. ->method('getContextValue');
  466. $contexts = [
  467. 'name' => $context,
  468. ];
  469. $context_definition = $this->createMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
  470. $plugin = $this->createMock('Drupal\Tests\Core\Plugin\TestConfigurableContextAwarePluginInterface');
  471. $plugin->expects($this->once())
  472. ->method('getContextMapping')
  473. ->willReturn([]);
  474. $plugin->expects($this->once())
  475. ->method('getContextDefinitions')
  476. ->will($this->returnValue(['hit' => $context_definition]));
  477. $plugin->expects($this->never())
  478. ->method('setContext');
  479. $this->expectException(ContextException::class);
  480. $this->expectExceptionMessage('Assigned contexts were not satisfied: miss');
  481. $this->contextHandler->applyContextMapping($plugin, $contexts, ['miss' => 'name']);
  482. }
  483. }
  484. interface TestConfigurableContextAwarePluginInterface extends ContextAwarePluginInterface, ConfigurableInterface, DependentPluginInterface {
  485. }
  486. class ContextAwarePluginDefinition extends PluginDefinition implements ContextAwarePluginDefinitionInterface {
  487. use ContextAwarePluginDefinitionTrait;
  488. }