Commit dd4e47f4 authored by berliner's avatar berliner Committed by Jakob P
Browse files

Issue #2810329 by manuel.adan, saniyat, stBorchert, andyg5000, joelpittet,...

Issue #2810329 by manuel.adan, saniyat, stBorchert, andyg5000, joelpittet, berliner: Page Manager paths should support optional arguments as well
parent cc894523
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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
+14 −13
Original line number Diff line number Diff line
@@ -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 = [
+39 −2
Original line number Diff line number Diff line
@@ -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],
@@ -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',
@@ -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.
   *
@@ -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);
+68 −0
Original line number Diff line number Diff line
@@ -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.
@@ -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());
  }

}
+20 −2
Original line number Diff line number Diff line
@@ -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[]
   */
@@ -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}
   */
@@ -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 = [];
@@ -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