diff --git a/page_manager.services.yml b/page_manager.services.yml index b1669e7..0697a1e 100644 --- a/page_manager.services.yml +++ b/page_manager.services.yml @@ -1,4 +1,7 @@ services: + page_manager.page_manager_helper: + class: Drupal\page_manager\PageManagerHelper + arguments: ['@token', '@entity.manager'] page_manager.current_user_context: class: Drupal\page_manager\EventSubscriber\CurrentUserContext arguments: ['@current_user', '@entity_type.manager'] diff --git a/page_manager_ui/src/Tests/PageManagerAdminTest.php b/page_manager_ui/src/Tests/PageManagerAdminTest.php index 715df72..70cfce8 100644 --- a/page_manager_ui/src/Tests/PageManagerAdminTest.php +++ b/page_manager_ui/src/Tests/PageManagerAdminTest.php @@ -1,7 +1,6 @@ install(['bartik', 'classy']); $this->config('system.theme')->set('admin', 'classy')->save(); - $this->drupalLogin($this->drupalCreateUser(['administer pages', 'access administration pages', 'view the administration theme'])); + $this->drupalLogin($this->drupalCreateUser([ + 'administer pages', + 'access administration pages', + 'view the administration theme' + ])); // Remove the default node_view page to start with a clean UI. Page::load('node_view')->delete(); @@ -124,7 +127,7 @@ class PageManagerAdminTest extends WebTestBase { $this->drupalGet('admin/foo'); $this->assertResponse(200); - $this->assertTitle('Foo | Drupal'); + $this->assertTitle('Status Code | Drupal'); // Change the status code to 403. $this->drupalGet('admin/structure/page_manager/manage/foo/page_variant__foo-http_status_code-0__general'); @@ -147,7 +150,7 @@ class PageManagerAdminTest extends WebTestBase { * * @param string $path * The path this step is supposed to be at. - * @param bool|TRUE $redirect + * @param bool|true $redirect * Whether or not to redirect to the path. */ protected function doTestAccessConditions($path = 'admin/structure/page_manager/manage/foo/access', $redirect = TRUE) { @@ -194,7 +197,7 @@ class PageManagerAdminTest extends WebTestBase { * * @param string $path * The path this step is supposed to be at. - * @param bool|TRUE $redirect + * @param bool|true $redirect * Whether or not to redirect to the path. */ protected function doTestSelectionCriteria($path = 'admin/structure/page_manager/manage/foo/page_variant__foo-http_status_code-0__selection', $redirect = TRUE) { diff --git a/src/Entity/PageVariant.php b/src/Entity/PageVariant.php index 58ad7f8..7852e4a 100644 --- a/src/Entity/PageVariant.php +++ b/src/Entity/PageVariant.php @@ -1,7 +1,6 @@ getVariantPluginCollection()->getConfiguration(); + return isset($config['page_title']) ? $config['page_title'] : $this->label(); + } + /** * {@inheritdoc} */ @@ -379,7 +386,7 @@ class PageVariant extends ConfigEntityBase implements PageVariantInterface { /** * {@inheritdoc} */ - public function setStaticContext($name, $configuration) { + public function setStaticContext($name, array $configuration) { $this->static_context[$name] = $configuration; $this->resetCollectedContexts(); return $this; @@ -432,7 +439,7 @@ class PageVariant extends ConfigEntityBase implements PageVariantInterface { /** * Wraps the condition plugin manager. * - * @return \Drupal\Core\Condition\ConditionManager + * @return \Drupal\Core\Condition\ConditionManager object */ protected function getConditionManager() { return \Drupal::service('plugin.manager.condition'); @@ -441,7 +448,7 @@ class PageVariant extends ConfigEntityBase implements PageVariantInterface { /** * Wraps the context mapper. * - * @return \Drupal\page_manager\ContextMapperInterface + * @return \Drupal\page_manager\ContextMapperInterface object */ protected function getContextMapper() { return \Drupal::service('page_manager.context_mapper'); @@ -450,7 +457,7 @@ class PageVariant extends ConfigEntityBase implements PageVariantInterface { /** * Wraps the page entity storage. * - * @return \Drupal\Core\Entity\EntityStorageInterface + * @return \Drupal\Core\Entity\EntityStorageInterface object */ protected function getPageStorage() { return \Drupal::entityTypeManager()->getStorage('page'); diff --git a/src/PageManagerHelper.php b/src/PageManagerHelper.php new file mode 100644 index 0000000..67d9159 --- /dev/null +++ b/src/PageManagerHelper.php @@ -0,0 +1,132 @@ +token = $token; + $this->entityManager = $entity_manager; + } + + /** + * Title callback for page variants. + * + * @param \Drupal\page_manager\PageVariantInterface $page_manager_page_variant + * The PageVariant entity. + * + * @return string + * The title of the page variant after replacing any tokens. + * + * @see \Drupal\page_manager\Routing\PageManagerRoutes::alterRoutes() + */ + public function getVariantTitle(PageVariantInterface $page_manager_page_variant = NULL) { + if ($page_manager_page_variant != NULL) { + return $this->getTitle($page_manager_page_variant->getTitle(), $page_manager_page_variant->getContexts()); + } + } + + /** + * Gets the title using given context and replaces tokens. + * + * @param string $title + * The title string. + * @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts + * An array of set context values, keyed by context name. + * + * @return string + * The title after replacing any tokens for given context. + */ + public function getTitle($title, array $contexts) { + $contexts = $this->fixContexts($contexts); + return $this->token->replace($title, $this->getContextAsTokenData($contexts)); + } + + /** + * Sometimes the contexts doesn't have the entity loaded. Fix them. + * + * @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts + * An array of set context values, keyed by context name. + * + * @return \Drupal\Core\Plugin\Context\ContextInterface[] + * Fixed contexts. + */ + protected function fixContexts(array $contexts) { + $fixed_contexts = []; + foreach ($contexts as $context_name => $context) { + $data_type = $context->getContextDefinition()->getDataType(); + if (preg_match('/entity:(\w+)/', $data_type, $matches)) { + $entity_type = $matches[1]; + if (is_numeric($context->getContextValue())) { + $storage = $this->entityManager->getStorage($entity_type); + $entity = $storage->load($context->getContextValue()); + if ($entity) { + $context = new Context($context->getContextDefinition(), $entity); + } + } + } + $fixed_contexts[$context_name] = $context; + } + return $fixed_contexts; + } + + /** + * Returns available context as token data. + * + * @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts + * An array of set context values, keyed by context name. + * + * @return array + * An array with token data values keyed by token type. + */ + protected function getContextAsTokenData(array $contexts) { + $data = []; + foreach ($contexts as $context) { + // @todo Simplify this when token and typed data types are unified in + // https://drupal.org/node/2163027. + if (strpos($context->getContextDefinition()->getDataType(), 'entity:') === 0) { + $token_type = substr($context->getContextDefinition()->getDataType(), 7); + if ($token_type == 'taxonomy_term') { + $token_type = 'term'; + } + $data[$token_type] = $context->getContextValue(); + } + } + return $data; + } + +} diff --git a/src/PageVariantInterface.php b/src/PageVariantInterface.php index d0cd19a..b0b452b 100644 --- a/src/PageVariantInterface.php +++ b/src/PageVariantInterface.php @@ -1,7 +1,6 @@ pageManagerHelper = $page_manager_helper; $this->moduleHandler = $module_handler; } @@ -88,7 +95,8 @@ class PageBlockDisplayVariant extends BlockDisplayVariant implements PluginWizar $container->get('token'), $container->get('plugin.manager.block'), $container->get('plugin.manager.condition'), - $container->get('module_handler') + $container->get('module_handler'), + $container->get('page_manager.page_manager_helper') ); } @@ -106,7 +114,7 @@ class PageBlockDisplayVariant extends BlockDisplayVariant implements PluginWizar } /** - * #pre_render callback for building the regions. + * Pre_render callback #pre_render for building the regions. */ public function buildRegions(array $build) { $cacheability = CacheableMetadata::createFromRenderArray($build) @@ -145,7 +153,11 @@ class PageBlockDisplayVariant extends BlockDisplayVariant implements PluginWizar '#block_plugin' => $block, '#pre_render' => [[$this, 'buildBlock']], '#cache' => [ - 'keys' => ['page_manager_block_display', $this->id(), 'block', $block_id], + 'keys' => [ + 'page_manager_block_display', + $this->id(), 'block', + $block_id + ], // Each block needs cache tags of the page and the block plugin, as // only the page is a config entity that will trigger cache tag // invalidations in case of block configuration changes. @@ -167,7 +179,7 @@ class PageBlockDisplayVariant extends BlockDisplayVariant implements PluginWizar } } - $build['#title'] = $this->renderPageTitle($this->configuration['page_title']); + $build['#title'] = $this->renderPageTitle($this->configuration['page_title'], $this->getContexts()); $cacheability->applyTo($build); @@ -175,7 +187,7 @@ class PageBlockDisplayVariant extends BlockDisplayVariant implements PluginWizar } /** - * #pre_render callback for building a block. + * Pre_render callback #pre_render for building a block. * * Renders the content using the provided block plugin, if there is no * content, aborts rendering, and makes sure the block won't be rendered. @@ -216,8 +228,7 @@ class PageBlockDisplayVariant extends BlockDisplayVariant implements PluginWizar // Don't call VariantBase::buildConfigurationForm() on purpose, because it // adds a 'Label' field that we don't actually want to use - we store the // label on the page variant entity. - //$form = parent::buildConfigurationForm($form, $form_state); - + // $form = parent::buildConfigurationForm($form, $form_state);. // Allow to configure the page title, even when adding a new display. // Default to the page label in that case. $form['page_title'] = [ @@ -280,36 +291,7 @@ class PageBlockDisplayVariant extends BlockDisplayVariant implements PluginWizar * The page title after replacing any tokens. */ protected function renderPageTitle($page_title) { - $data = $this->getContextAsTokenData(); - // Token replace only escapes replacement values, ensure a consistent - // behavior by also escaping the input and then returning it as a Markup - // object to avoid double escaping. - // @todo: Simplify this when core provides an API for this in - // https://www.drupal.org/node/2580723. - $title = (string) $this->token->replace(new HtmlEscapedText($page_title), $data); - return Markup::create($title); - } - - /** - * Returns available context as token data. - * - * @return array - * An array with token data values keyed by token type. - */ - protected function getContextAsTokenData() { - $data = []; - foreach ($this->getContexts() as $context) { - // @todo Simplify this when token and typed data types are unified in - // https://drupal.org/node/2163027. - if (strpos($context->getContextDefinition()->getDataType(), 'entity:') === 0) { - $token_type = substr($context->getContextDefinition()->getDataType(), 7); - if ($token_type == 'taxonomy_term') { - $token_type = 'term'; - } - $data[$token_type] = $context->getContextValue(); - } - } - return $data; + return $this->pageManagerHelper->getTitle($page_title, $this->getContexts()); } /** @@ -336,4 +318,11 @@ class PageBlockDisplayVariant extends BlockDisplayVariant implements PluginWizar return $vars; } + /** + * {@inheritdoc} + */ + public function getTitle() { + return $this->configuration['page_title'] ?: $this->label(); + } + } diff --git a/src/Routing/PageManagerRoutes.php b/src/Routing/PageManagerRoutes.php index 7def0d8..0c85c7c 100644 --- a/src/Routing/PageManagerRoutes.php +++ b/src/Routing/PageManagerRoutes.php @@ -1,7 +1,6 @@ label(); + $defaults['_title_callback'] = 'page_manager.page_manager_helper:getVariantTitle'; $defaults['page_manager_page'] = $entity->id(); $parameters['page_manager_page_variant']['type'] = 'entity:page_variant'; $parameters['page_manager_page']['type'] = 'entity:page'; diff --git a/tests/src/Unit/PageBlockDisplayVariantTest.php b/tests/src/Unit/PageBlockDisplayVariantTest.php index 2a140ea..8381823 100644 --- a/tests/src/Unit/PageBlockDisplayVariantTest.php +++ b/tests/src/Unit/PageBlockDisplayVariantTest.php @@ -1,7 +1,6 @@ access($account)->willReturn(TRUE); // Building a block with empty content. - $block1->build()->willReturn(['#cache' => [ 'tags' => [ 0 => 'tag_to_be_merged']]]); + $block1->build()->willReturn(['#cache' => ['tags' => [0 => 'tag_to_be_merged']]]); $context_handler = $this->prophesize(ContextHandlerInterface::class); $uuid_generator = $this->prophesize(UuidInterface::class); @@ -55,8 +54,9 @@ class PageBlockDisplayVariantTest extends UnitTestCase { $block_manager = $this->prophesize(BlockManager::class); $condition_manager = $this->prophesize(ConditionManager::class); $module_handler = $this->prophesize(ModuleHandlerInterface::class); + $page_manager_helper = $this->prophesize(PageManagerHelper::class); - $variant_plugin = new PageBlockDisplayVariant([], '', [], $context_handler->reveal(), $account->reveal(), $uuid_generator->reveal(), $token->reveal(), $block_manager->reveal(), $condition_manager->reveal(), $module_handler->reveal()); + $variant_plugin = new PageBlockDisplayVariant([], '', [], $context_handler->reveal(), $account->reveal(), $uuid_generator->reveal(), $token->reveal(), $block_manager->reveal(), $condition_manager->reveal(), $module_handler->reveal(), $page_manager_helper->reveal()); // Empty block. $expected_build = [ @@ -152,8 +152,24 @@ class PageBlockDisplayVariantTest extends UnitTestCase { ->getMock(); $block_manager = $this->prophesize(BlockManager::class); $condition_manager = $this->prophesize(ConditionManager::class); + $page_manager_helper = $this->prophesize(PageManagerHelper::class); $variant_plugin = $this->getMockBuilder(PageBlockDisplayVariant::class) - ->setConstructorArgs([['page_title' => $page_title, 'uuid' => 'UUID'], 'test', [], $context_handler->reveal(), $account->reveal(), $uuid_generator->reveal(), $token, $block_manager->reveal(), $condition_manager->reveal(), $module_handler->reveal()]) + ->setConstructorArgs( + [ + [ + 'page_title' => $page_title, + 'uuid' => 'UUID', + ], + 'test', + [], + $context_handler->reveal(), + $account->reveal(), + $uuid_generator->reveal(), + $token, $block_manager->reveal(), + $condition_manager->reveal(), + $module_handler->reveal(), + $page_manager_helper->reveal(), + ]) ->setMethods(['renderPageTitle']) ->getMock(); @@ -219,8 +235,9 @@ class PageBlockDisplayVariantTest extends UnitTestCase { $block_manager = $this->prophesize(BlockManager::class); $condition_manager = $this->prophesize(ConditionManager::class); $module_handler = $this->prophesize(ModuleHandlerInterface::class); + $page_manager_helper = $this->prophesize(PageManagerHelper::class); - $variant_plugin = new PageBlockDisplayVariant([], '', [], $context_handler->reveal(), $account->reveal(), $uuid_generator->reveal(), $token->reveal(), $block_manager->reveal(), $condition_manager->reveal(), $module_handler->reveal()); + $variant_plugin = new PageBlockDisplayVariant([], '', [], $context_handler->reveal(), $account->reveal(), $uuid_generator->reveal(), $token->reveal(), $block_manager->reveal(), $condition_manager->reveal(), $module_handler->reveal(), $page_manager_helper->reveal()); $values = ['page_title' => "Go hang a salami, I'm a lasagna hog!"]; diff --git a/tests/src/Unit/PageManagerRoutesTest.php b/tests/src/Unit/PageManagerRoutesTest.php index d0fff14..4497408 100644 --- a/tests/src/Unit/PageManagerRoutesTest.php +++ b/tests/src/Unit/PageManagerRoutesTest.php @@ -1,7 +1,6 @@ getVariants() ->willReturn(['variant1' => $variant1->reveal()]); $page1->label() - ->willReturn('Page label') - ->shouldBeCalled(); + ->shouldNotBeCalled(); $page1->usesAdminTheme() ->willReturn(TRUE) ->shouldBeCalled(); @@ -130,7 +128,7 @@ class PageManagerRoutesTest extends UnitTestCase { $route = $collection->get('page_manager.page_view_page1_variant1'); $expected_defaults = [ '_entity_view' => 'page_manager_page_variant', - '_title' => 'Page label', + '_title_callback' => 'page_manager.page_manager_helper:getVariantTitle', 'page_manager_page_variant' => 'variant1', 'page_manager_page' => 'page1', 'page_manager_page_variant_weight' => 0, @@ -203,12 +201,12 @@ class PageManagerRoutesTest extends UnitTestCase { 'test_route.POST_with_format', 'test_route', 'page_manager.page_view_page1_variant1', - ], array_keys($collection->all())); + ], array_keys($collection->all())); $route = $collection->get('page_manager.page_view_page1_variant1'); $expected_defaults = [ '_entity_view' => 'page_manager_page_variant', - '_title' => NULL, + '_title_callback' => 'page_manager.page_manager_helper:getVariantTitle', 'page_manager_page_variant' => 'variant1', 'page_manager_page' => 'page1', 'page_manager_page_variant_weight' => 0, @@ -232,14 +230,29 @@ class PageManagerRoutesTest extends UnitTestCase { $this->assertMatchingRoute($route, $existing_route_path, $expected_defaults, $expected_requirements, $expected_options); } + /** + * Tests alter overriding an existing route. + * + * @covers ::alterRoutes + */ public function providerTestAlterRoutesOverrideExisting() { $data = []; $data['no_slug'] = ['/test_route', '/test_route']; $data['slug'] = ['/test_route/{test_route}', '/test_route/{test_route}']; $data['placeholder'] = ['/test_route/%', '/test_route/{test_route}']; - $data['slug_with_default'] = ['/test_route/{default_exists}', '/test_route/{default_exists}']; - $data['placeholder_with_default'] = ['/test_route/%', '/test_route/{default_exists}']; - $data['with_requirement'] = ['/test_route/{foo}', '/test_route/{foo}', ['foo' => '\d+']]; + $data['slug_with_default'] = [ + '/test_route/{default_exists}', + '/test_route/{default_exists}' + ]; + $data['placeholder_with_default'] = [ + '/test_route/%', + '/test_route/{default_exists}' + ]; + $data['with_requirement'] = [ + '/test_route/{foo}', + '/test_route/{foo}', + ['foo' => '\d+'] + ]; return $data; } @@ -280,12 +293,11 @@ class PageManagerRoutesTest extends UnitTestCase { 'test_route', 'page_manager.page_view_page1_variant1', 'page_manager.page_view_page2_variant2', - ], array_keys($collection->all())); + ], array_keys($collection->all())); $expected = [ 'test_route' => [ 'path' => '/test_route1', - 'defaults' => [ - ], + 'defaults' => [], 'requirements' => [ '_access' => 'TRUE', ], @@ -297,7 +309,7 @@ class PageManagerRoutesTest extends UnitTestCase { 'path' => '/test_route1', 'defaults' => [ '_entity_view' => 'page_manager_page_variant', - '_title' => 'Page 1', + '_title_callback' => 'page_manager.page_manager_helper:getVariantTitle', 'page_manager_page_variant' => 'variant1', 'page_manager_page' => 'page1', 'page_manager_page_variant_weight' => 0, @@ -325,7 +337,7 @@ class PageManagerRoutesTest extends UnitTestCase { 'path' => '/test_route2', 'defaults' => [ '_entity_view' => 'page_manager_page_variant', - '_title' => 'Page 2', + '_title_callback' => 'page_manager.page_manager_helper:getVariantTitle', 'page_manager_page_variant' => 'variant2', 'page_manager_page' => 'page2', 'page_manager_page_variant_weight' => 0, @@ -371,7 +383,18 @@ class PageManagerRoutesTest extends UnitTestCase { $page->id()->willReturn('page1'); $page->label()->willReturn(NULL); $page->usesAdminTheme()->willReturn(FALSE); - $page->getParameters()->willReturn(['foo' => ['machine_name' => 'foo', 'type' => 'integer', 'label' => 'Foo'], 'test_route' => ['machine_name' => 'test_route', 'type' => '', 'label' => '']]); + $page->getParameters()->willReturn([ + 'foo' => [ + 'machine_name' => 'foo', + 'type' => 'integer', + 'label' => 'Foo' + ], + 'test_route' => [ + 'machine_name' => 'test_route', + 'type' => '', + 'label' => '' + ] + ]); $variant1 = $this->prophesize(PageVariantInterface::class); $variant1->getWeight()->willReturn(0); @@ -386,7 +409,7 @@ class PageManagerRoutesTest extends UnitTestCase { $expected_defaults = [ '_entity_view' => 'page_manager_page_variant', - '_title' => NULL, + '_title_callback' => 'page_manager.page_manager_helper:getVariantTitle', 'page_manager_page_variant' => 'variant1', 'page_manager_page' => 'page1', 'page_manager_page_variant_weight' => 0,