Unable to create URL aliases with XB enabled

Created on 30 January 2025, 3 days ago

Overview

Note that this happens in the regular not-XB node form.
When the XB module is enabled, any attempt to update the URL alias field in a node will hit the ValidPathConstraint and error with the following
"Either the path <ALIAS-YOU-ARE-TRYING-TO-MAKE> is invalid or you do not have access to it."

Proposed resolution

User interface changes

🐛 Bug report
Status

Active

Version

0.0

Component

Code

Created by

🇺🇸United States bnjmnm Ann Arbor, MI

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @bnjmnm
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    Surprising this is only surfacing now, because the root cause has been around since April 10, 2024! 🤯

    Root cause: \Drupal\experience_builder\Plugin\Field\FieldTypeOverride\PathItemOverride::propertyDefinitions(), which does:

      public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
        $properties = parent::propertyDefinitions($field_definition);
        $properties['alias']->addConstraint('ValidPath');
        return $properties;
      }
    

    To be investigated why that prevents this from working 😬

  • 🇬🇧United Kingdom jessebaker

    I just found it now because I'm implementing the "Publish all changes" button and the tests (that I'm writing) for that cannot pass because it's currently not possible to publish changes due to this issue!

  • 🇺🇸United States mglaman WI, USA

    I thought we had an issue about this, sorry! It's documented in https://git.drupalcode.org/project/experience_builder/-/blob/0.x/tests/s... and we ran into it while working on Creating a page generates the URL path dynamically when editing. Active

        // Path field is always invalid for new entities.
        // @see \Drupal\path\Plugin\Field\FieldWidget\PathWidget::validateFormElement().
    

    The widget excludes the violation if it's a new entity. I was hoping JSON:API had a fix for this

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    I was hoping JSON:API had a fix for this

    See #2 — it's an XB-specific constraint addition for shape matching purposes. 😅

  • 🇬🇧United Kingdom jessebaker

    Added related issue and updated summary.

  • First commit to issue fork.
  • Merge request !596Remove PathItemOverride. → (Merged) created by longwave
  • 🇬🇧United Kingdom longwave UK

    PathItemOverride is doing the opposite of what we think it's doing: ValidPath checks that the path is in use and will return a valid page instead of a 404. But when setting an alias we explicitly don't need or want that to happen!

    It's not clear from commit history or comments exactly why this is here, so let's just remove it for now?

  • 🇬🇧United Kingdom longwave UK

    It's struck me that the intent of this is that the alias is a valid alias, rather than a path, so we can do that.

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    This is hard-blocking #3497530 — see #3497530-16: [PP-1] Implement the "Publish All" button .

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    It's not clear from commit history or comments exactly why this is here, so let's just remove it for now?

    😬🙈 That code dates back to the earliest XB days: https://wimleers.com/xb-week-5#chaos-origin — I know where to dig to answer that.

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    See how commit eab37106 added this test expectation:

            '⿲sdc_test_all_props:all-props␟test-string-format-' . JsonSchemaStringFormat::URI_REFERENCE->value => [
              'storage' => $all_string_storage_props,
              'format' => [
                'ℹ︎path␟alias',
              ],
            ],
    

    (Which means the path field type's alias property is a match.)

    This then evolved in subsequent commits to:

            'optional, type=string&format=uri-reference' => [
              'component props' => [
                '⿲sdc_test_all_props:all-props␟test_string_format_' . str_replace('-', '_', JsonSchemaStringFormat::URI_REFERENCE->value),
              ],
              'storage' => $all_string_storage_props,
              'format_any_prop' => [
                'ℹ︎path␟alias',
              ],
              'format_main_prop' => [
                'ℹ︎path␟alias',
              ],
              'instances' => [
                'ℹ︎␜entity:node:foo␝path␞␟alias',
                'ℹ︎␜entity:path_alias␝path␞␟value',
              ],
              'adapter_matches_field_type' => [],
              'adapter_matches_instance' => [],
            ],
    

    Which shows that it found actual FieldConfigs ("field instances") that provide this.

    It is 📌 Fix the visually broken "image" component instance: use FileUriItem's computed `url` property, not the stored `value` property Active that made the drastic change, from what's quoted above to:

            'optional, type=string&format=uri-reference' => [
              'component props' => [
                '⿲sdc_test_all_props:all-props␟test_string_format_' . str_replace('-', '_', JsonSchemaStringFormat::URI_REFERENCE->value),
              ],
              'storage' => $all_string_storage_props,
              'format_any_prop' => [
                'ℹ︎file_uri␟url',
                'ℹ︎file_uri␟value',
                'ℹ︎file␟entity␜␜entity:file␝uri␞0␟url',
                'ℹ︎file␟entity␜␜entity:file␝uri␞0␟value',
                'ℹ︎image␟entity␜␜entity:file␝uri␞0␟url',
                'ℹ︎image␟entity␜␜entity:file␝uri␞0␟value',
                'ℹ︎link␟uri',
                'ℹ︎uri␟value',
              ],
              'format_main_prop' => [
                'ℹ︎file_uri␟value',
                'ℹ︎file␟entity␜␜entity:file␝uri␞0␟url',
                'ℹ︎file␟entity␜␜entity:file␝uri␞0␟value',
                'ℹ︎image␟entity␜␜entity:file␝uri␞0␟url',
                'ℹ︎image␟entity␜␜entity:file␝uri␞0␟value',
                'ℹ︎link␟uri',
                'ℹ︎uri␟value',
              ],
              'instances' => [
                'ℹ︎␜entity:file␝uri␞␟url',
                'ℹ︎␜entity:file␝uri␞␟value',
                'ℹ︎␜entity:node:foo␝field_silly_image␞␟entity␜␜entity:file␝uri␞␟url',
                'ℹ︎␜entity:node:foo␝field_silly_image␞␟entity␜␜entity:file␝uri␞␟value',
              ],
              'adapter_matches_field_type' => [],
              'adapter_matches_instance' => [],
            ],
    

    That's powered by this change in that commit:

           // TRICKY: Drupal core does not support RFC3987 aka IRIs, but it's a superset of RFC3986.
    -      static::URI, static::IRI => new DataTypeShapeRequirement('PrimitiveType', [], UriInterface::class),
    -      // @todo Verify that \Drupal\Core\Path\Plugin\Validation\Constraint\ValidPathConstraintValidator matches this close enough.
    -      static::URI_REFERENCE, static::IRI_REFERENCE => new DataTypeShapeRequirement('ValidPath', []),
    +      static::URI_REFERENCE, static::URI, static::IRI, static::IRI_REFERENCE => new DataTypeShapeRequirement('PrimitiveType', [], UriInterface::class),
    

    As of that moment, XB's PathItemOverride indeed became obsolete and should've been removed 🙈😬

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • Pipeline finished with Skipped
    1 day ago
    #411129
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    @longwave in #10:

    It's struck me that the intent of this is that the alias is a valid alias, rather than a path, so we can do that.

    That was indeed the intent. And

    static::URI_REFERENCE, static::URI, static::IRI, static::IRI_REFERENCE => new DataTypeShapeRequirement('PrimitiveType', [], UriInterface::class),
    

    in \Drupal\experience_builder\JsonSchemaInterpreter\JsonSchemaStringFormat::toDataTypeShapeRequirements() is not actually validating that, because \Drupal\Core\Validation\Plugin\Validation\Constraint\PrimitiveTypeConstraintValidator::validate() does this utterly baffling thing:

        // Ensure that URIs comply with http://tools.ietf.org/html/rfc3986, which
        // requires:
        // - That it is well formed (parse_url() returns FALSE if not).
        // - That it contains a scheme (parse_url(, PHP_URL_SCHEME) returns NULL if
        //   not).
        if ($typed_data instanceof UriInterface && in_array(parse_url($value, PHP_URL_SCHEME), [NULL, FALSE], TRUE)) {
          $valid = FALSE;
        }
    

    Essentially, what we need eventually, is better validation than that. More precise. But that's not an immediate concern.

    So: could you please open a follow-up if you already were working on a solution for that? 🤓🙏

Production build 0.71.5 2024