Loading config/schema/page_manager.schema.yml +3 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,9 @@ page_manager.page.*: type: type: string label: 'Context type' optional: type: boolean label: 'Optional' page_manager.page_variant.*: type: config_entity Loading page_manager_ui/src/Form/PageParametersForm.php +14 −13 Original line number Diff line number Diff line Loading @@ -36,32 +36,33 @@ class PageParametersForm extends FormBase { $this->t('Machine name'), $this->t('Label'), $this->t('Type'), $this->t('Optional'), $this->t('Operations'), ], '#rows' => $this->renderRows($cached_values), '#rows' => $this->renderRows($cached_values, $form, $form_state), '#empty' => $this->t('There are no parameters defined for this page.'), ]; return $form; } protected function renderRows($cached_values) { protected function renderRows($cached_values, array &$form, FormStateInterface $form_state) { $rows = []; /** @var $page \Drupal\page_manager\Entity\Page */ /** @var \Drupal\page_manager\Entity\Page $page */ $page = $cached_values['page']; /** * @var string $parameter */ foreach ($page->getParameterNames() as $parameter_name) { $parameter = $page->getParameter($parameter_name); // Use parameter defaults for new parameters. if (empty($parameter)) { $parameter = (array) $page->parameterDefaults(); } $parameter += ['optional' => FALSE]; $row = []; $row['machine_name'] = $parameter['machine_name'] ?? ''; if ($label = $parameter['label'] ?? '') { $row['label'] = $label; } else { $row['type']['colspan'] = 2; } $row['type']['data'] = isset($parameter['type']) ?: $this->t('<em>No context assigned</em>'); $row['label'] = $parameter['label'] ?? ''; $row['type']['data'] = $parameter['type'] ?: $this->t('<em>No context assigned</em>'); $row['optional'] = $parameter['optional'] ? $this->t('Optional') : $this->t('Required'); [$route_partial, $route_parameters] = $this->getOperationsRouteInfo($cached_values, $cached_values['id'], $parameter_name); $build = [ Loading page_manager_ui/src/Form/ParameterEditForm.php +39 −2 Original line number Diff line number Diff line Loading @@ -136,7 +136,7 @@ class ParameterEditForm extends FormBase { $form['label'] = [ '#type' => 'textfield', '#title' => $this->t('Label'), '#default_value' => isset($parameter['label']) ?: ucfirst($parameter['machine_name'] ?? ''), '#default_value' => !empty($parameter['label']) ? $parameter['label'] : (ucfirst($parameter['machine_name'] ?? '')), '#states' => [ 'invisible' => [ ':input[name="type"]' => ['value' => static::NO_CONTEXT_KEY], Loading @@ -152,6 +152,12 @@ class ParameterEditForm extends FormBase { '#default_value' => $parameter['type'] ?? '', ]; $form['optional'] = [ '#type' => 'checkbox', '#title' => $this->t('Optional'), '#default_value' => !empty($parameter['optional']), ]; $form['actions'] = ['#type' => 'actions']; $form['actions']['submit'] = [ '#type' => 'submit', Loading @@ -162,6 +168,36 @@ class ParameterEditForm extends FormBase { return $form; } /** * {@inheritdoc} */ public function validateForm(array &$form, FormStateInterface $form_state) { $cached_values = $this->getTempstore(); /** @var \Drupal\page_manager\PageInterface $page */ $page = $cached_values['page']; $edited_parameter_name = $form_state->getValue('machine_name'); $edited_parameter_optional = $form_state->getValue('optional'); // Checks that no optional parameter is before a required one. $required_allowed = TRUE; foreach ($page->getParameterNames() as $parameter_name) { $parameter = $page->getParameter($parameter_name); $parameter_optional = $parameter_name == $edited_parameter_name ? $edited_parameter_optional : !empty($parameter['optional']); if ($parameter_optional) { $required_allowed = FALSE; } elseif (!$required_allowed) { $form_state->setErrorByName('optional', $this->t('Optional path parameters not allowed before required parameters.')); } } parent::validateForm($form, $form_state); } /** * Builds an array of options for the parameter type. * Loading Loading @@ -201,13 +237,14 @@ class ParameterEditForm extends FormBase { $page = $cache_values['page']; $name = $form_state->getValue('machine_name'); $type = $form_state->getValue('type'); $optional = $form_state->getValue('optional'); if ($type === static::NO_CONTEXT_KEY) { $page->removeParameter($name); $label = NULL; } else { $label = $form_state->getValue('label'); $page->setParameter($name, $type, $label); $page->setParameter($name, $type, $label, $optional); } $this->setTempstore($cache_values); Loading page_manager_ui/tests/src/Functional/PageParametersTest.php +68 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,14 @@ class PageParametersTest extends BrowserTestBase { * Tests page parameters when adding a page and when editing it. */ public function testParameters() { $this->doTestAddParameter(); $this->doTestOptionalParameters(); } /** * Tests page parameters when adding a page and when editing it. */ public function doTestAddParameter() { $node = $this->drupalCreateNode(['type' => 'article']); // Create a page. Loading Loading @@ -100,4 +108,64 @@ class PageParametersTest extends BrowserTestBase { $this->assertSession()->pageTextContains($node->getTitle()); } /** * Tests optional parameters. * * @param string $path * The path this step is supposed to be at. * @param bool|TRUE $redirect * Whether or not to redirect to the path. */ protected function doTestOptionalParameters($path = 'admin/structure/page_manager/manage/foo/general', $redirect = TRUE) { if ($this->getUrl() !== $path && $redirect) { $this->drupalGet($path); } $this->assertTitle('Page information | Drupal'); $node = $this->drupalCreateNode(['type' => 'article']); // Add extra parameter. $edit = [ 'path' => 'admin/foo/{node}/{extra}', ]; $this->drupalPostForm(NULL, $edit, 'Update and save'); $this->assertText('The page Foo has been updated.'); $this->drupalGet('admin/structure/page_manager/manage/foo/parameter/edit/extra'); $edit = [ 'label' => 'Extra', 'type' => 'string', 'optional' => FALSE, ]; $this->drupalPostForm(NULL, $edit, 'Update parameter'); $this->assertText('The Extra parameter has been updated.'); $this->drupalPostForm(NULL, [], 'Update and save'); $this->assertText('The page Foo has been updated.'); // Check the required extra parameter. $this->drupalGet('admin/foo/' . $node->id()); $this->assertResponse(404); $this->drupalGet('admin/foo/' . $node->id() . '/' . $this->randomMachineName()); $this->assertResponse(200); $this->assertText($node->getTitle()); // Set the extra parameter as optional. $this->drupalGet('admin/structure/page_manager/manage/foo/parameter/edit/extra'); $edit = [ 'optional' => TRUE, ]; $this->drupalPostForm(NULL, $edit, 'Update parameter'); $this->assertText('The Extra parameter has been updated.'); $this->drupalPostForm(NULL, [], 'Update and save'); $this->assertText('The page Foo has been updated.'); // Check the extra parameter is optional. $this->drupalGet('admin/foo/' . $node->id()); $this->assertResponse(200); $this->assertText($node->getTitle()); $this->drupalGet('admin/foo/' . $node->id() . '/' . $this->randomMachineName()); $this->assertResponse(200); $this->assertText($node->getTitle()); } } src/Entity/Page.php +20 −2 Original line number Diff line number Diff line Loading @@ -121,6 +121,7 @@ class Page extends ConfigEntityBase implements PageInterface { * - machine_name: Machine-readable context name. * - label: Human-readable context name. * - type: Context type. * - optional: Whether the parameter is optional. * * @var array[] */ Loading Loading @@ -243,6 +244,21 @@ class Page extends ConfigEntityBase implements PageInterface { return []; } /** * Defaults for new parameters. * * @return array * An array of default parameter values. */ public function parameterDefaults() { return [ 'type' => '', 'machine_name' => '', 'label' => '', 'optional' => FALSE, ]; } /** * {@inheritdoc} */ Loading @@ -263,11 +279,12 @@ class Page extends ConfigEntityBase implements PageInterface { /** * {@inheritdoc} */ public function setParameter($name, $type, $label = '') { public function setParameter($name, $type, $label = '', $optional = FALSE) { $this->parameters[$name] = [ 'machine_name' => $name, 'type' => $type, 'label' => $label, 'optional' => $optional, ]; // Reset contexts when a parameter is added or changed. $this->contexts = []; Loading Loading @@ -352,7 +369,8 @@ class Page extends ConfigEntityBase implements PageInterface { $cacheability->setCacheContexts(['route']); $context_definition = ContextDefinitionFactory::create($configuration['type']) ->setLabel($configuration['label']); ->setLabel($configuration['label']) ->setRequired(empty($configuration['optional'])); $context = new Context($context_definition); $context->addCacheableDependency($cacheability); $this->contexts[$machine_name] = $context; Loading Loading
config/schema/page_manager.schema.yml +3 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,9 @@ page_manager.page.*: type: type: string label: 'Context type' optional: type: boolean label: 'Optional' page_manager.page_variant.*: type: config_entity Loading
page_manager_ui/src/Form/PageParametersForm.php +14 −13 Original line number Diff line number Diff line Loading @@ -36,32 +36,33 @@ class PageParametersForm extends FormBase { $this->t('Machine name'), $this->t('Label'), $this->t('Type'), $this->t('Optional'), $this->t('Operations'), ], '#rows' => $this->renderRows($cached_values), '#rows' => $this->renderRows($cached_values, $form, $form_state), '#empty' => $this->t('There are no parameters defined for this page.'), ]; return $form; } protected function renderRows($cached_values) { protected function renderRows($cached_values, array &$form, FormStateInterface $form_state) { $rows = []; /** @var $page \Drupal\page_manager\Entity\Page */ /** @var \Drupal\page_manager\Entity\Page $page */ $page = $cached_values['page']; /** * @var string $parameter */ foreach ($page->getParameterNames() as $parameter_name) { $parameter = $page->getParameter($parameter_name); // Use parameter defaults for new parameters. if (empty($parameter)) { $parameter = (array) $page->parameterDefaults(); } $parameter += ['optional' => FALSE]; $row = []; $row['machine_name'] = $parameter['machine_name'] ?? ''; if ($label = $parameter['label'] ?? '') { $row['label'] = $label; } else { $row['type']['colspan'] = 2; } $row['type']['data'] = isset($parameter['type']) ?: $this->t('<em>No context assigned</em>'); $row['label'] = $parameter['label'] ?? ''; $row['type']['data'] = $parameter['type'] ?: $this->t('<em>No context assigned</em>'); $row['optional'] = $parameter['optional'] ? $this->t('Optional') : $this->t('Required'); [$route_partial, $route_parameters] = $this->getOperationsRouteInfo($cached_values, $cached_values['id'], $parameter_name); $build = [ Loading
page_manager_ui/src/Form/ParameterEditForm.php +39 −2 Original line number Diff line number Diff line Loading @@ -136,7 +136,7 @@ class ParameterEditForm extends FormBase { $form['label'] = [ '#type' => 'textfield', '#title' => $this->t('Label'), '#default_value' => isset($parameter['label']) ?: ucfirst($parameter['machine_name'] ?? ''), '#default_value' => !empty($parameter['label']) ? $parameter['label'] : (ucfirst($parameter['machine_name'] ?? '')), '#states' => [ 'invisible' => [ ':input[name="type"]' => ['value' => static::NO_CONTEXT_KEY], Loading @@ -152,6 +152,12 @@ class ParameterEditForm extends FormBase { '#default_value' => $parameter['type'] ?? '', ]; $form['optional'] = [ '#type' => 'checkbox', '#title' => $this->t('Optional'), '#default_value' => !empty($parameter['optional']), ]; $form['actions'] = ['#type' => 'actions']; $form['actions']['submit'] = [ '#type' => 'submit', Loading @@ -162,6 +168,36 @@ class ParameterEditForm extends FormBase { return $form; } /** * {@inheritdoc} */ public function validateForm(array &$form, FormStateInterface $form_state) { $cached_values = $this->getTempstore(); /** @var \Drupal\page_manager\PageInterface $page */ $page = $cached_values['page']; $edited_parameter_name = $form_state->getValue('machine_name'); $edited_parameter_optional = $form_state->getValue('optional'); // Checks that no optional parameter is before a required one. $required_allowed = TRUE; foreach ($page->getParameterNames() as $parameter_name) { $parameter = $page->getParameter($parameter_name); $parameter_optional = $parameter_name == $edited_parameter_name ? $edited_parameter_optional : !empty($parameter['optional']); if ($parameter_optional) { $required_allowed = FALSE; } elseif (!$required_allowed) { $form_state->setErrorByName('optional', $this->t('Optional path parameters not allowed before required parameters.')); } } parent::validateForm($form, $form_state); } /** * Builds an array of options for the parameter type. * Loading Loading @@ -201,13 +237,14 @@ class ParameterEditForm extends FormBase { $page = $cache_values['page']; $name = $form_state->getValue('machine_name'); $type = $form_state->getValue('type'); $optional = $form_state->getValue('optional'); if ($type === static::NO_CONTEXT_KEY) { $page->removeParameter($name); $label = NULL; } else { $label = $form_state->getValue('label'); $page->setParameter($name, $type, $label); $page->setParameter($name, $type, $label, $optional); } $this->setTempstore($cache_values); Loading
page_manager_ui/tests/src/Functional/PageParametersTest.php +68 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,14 @@ class PageParametersTest extends BrowserTestBase { * Tests page parameters when adding a page and when editing it. */ public function testParameters() { $this->doTestAddParameter(); $this->doTestOptionalParameters(); } /** * Tests page parameters when adding a page and when editing it. */ public function doTestAddParameter() { $node = $this->drupalCreateNode(['type' => 'article']); // Create a page. Loading Loading @@ -100,4 +108,64 @@ class PageParametersTest extends BrowserTestBase { $this->assertSession()->pageTextContains($node->getTitle()); } /** * Tests optional parameters. * * @param string $path * The path this step is supposed to be at. * @param bool|TRUE $redirect * Whether or not to redirect to the path. */ protected function doTestOptionalParameters($path = 'admin/structure/page_manager/manage/foo/general', $redirect = TRUE) { if ($this->getUrl() !== $path && $redirect) { $this->drupalGet($path); } $this->assertTitle('Page information | Drupal'); $node = $this->drupalCreateNode(['type' => 'article']); // Add extra parameter. $edit = [ 'path' => 'admin/foo/{node}/{extra}', ]; $this->drupalPostForm(NULL, $edit, 'Update and save'); $this->assertText('The page Foo has been updated.'); $this->drupalGet('admin/structure/page_manager/manage/foo/parameter/edit/extra'); $edit = [ 'label' => 'Extra', 'type' => 'string', 'optional' => FALSE, ]; $this->drupalPostForm(NULL, $edit, 'Update parameter'); $this->assertText('The Extra parameter has been updated.'); $this->drupalPostForm(NULL, [], 'Update and save'); $this->assertText('The page Foo has been updated.'); // Check the required extra parameter. $this->drupalGet('admin/foo/' . $node->id()); $this->assertResponse(404); $this->drupalGet('admin/foo/' . $node->id() . '/' . $this->randomMachineName()); $this->assertResponse(200); $this->assertText($node->getTitle()); // Set the extra parameter as optional. $this->drupalGet('admin/structure/page_manager/manage/foo/parameter/edit/extra'); $edit = [ 'optional' => TRUE, ]; $this->drupalPostForm(NULL, $edit, 'Update parameter'); $this->assertText('The Extra parameter has been updated.'); $this->drupalPostForm(NULL, [], 'Update and save'); $this->assertText('The page Foo has been updated.'); // Check the extra parameter is optional. $this->drupalGet('admin/foo/' . $node->id()); $this->assertResponse(200); $this->assertText($node->getTitle()); $this->drupalGet('admin/foo/' . $node->id() . '/' . $this->randomMachineName()); $this->assertResponse(200); $this->assertText($node->getTitle()); } }
src/Entity/Page.php +20 −2 Original line number Diff line number Diff line Loading @@ -121,6 +121,7 @@ class Page extends ConfigEntityBase implements PageInterface { * - machine_name: Machine-readable context name. * - label: Human-readable context name. * - type: Context type. * - optional: Whether the parameter is optional. * * @var array[] */ Loading Loading @@ -243,6 +244,21 @@ class Page extends ConfigEntityBase implements PageInterface { return []; } /** * Defaults for new parameters. * * @return array * An array of default parameter values. */ public function parameterDefaults() { return [ 'type' => '', 'machine_name' => '', 'label' => '', 'optional' => FALSE, ]; } /** * {@inheritdoc} */ Loading @@ -263,11 +279,12 @@ class Page extends ConfigEntityBase implements PageInterface { /** * {@inheritdoc} */ public function setParameter($name, $type, $label = '') { public function setParameter($name, $type, $label = '', $optional = FALSE) { $this->parameters[$name] = [ 'machine_name' => $name, 'type' => $type, 'label' => $label, 'optional' => $optional, ]; // Reset contexts when a parameter is added or changed. $this->contexts = []; Loading Loading @@ -352,7 +369,8 @@ class Page extends ConfigEntityBase implements PageInterface { $cacheability->setCacheContexts(['route']); $context_definition = ContextDefinitionFactory::create($configuration['type']) ->setLabel($configuration['label']); ->setLabel($configuration['label']) ->setRequired(empty($configuration['optional'])); $context = new Context($context_definition); $context->addCacheableDependency($cacheability); $this->contexts[$machine_name] = $context; Loading