Problem/Motivation

NOTE: Discussion on this issue is time-boxed to the next beta, beta7.

  • In HEAD, we have a Url::fromUri() method for creating a $url object from a URI string. The URI string that is passed in must be absolute (start with a scheme name). The scheme name may either be a common IANA-registered one, such as http, or a non-IANA-registered one defined by Drupal. The current Drupal-defined ones are: base, user-path, entity, and route. These scheme names are private to Drupal; they unify the different kinds of things that Drupal needs to generate URLs for, but when the URL is finally output to the browser, it is output as a URL that the browser can understand (either a relative URL or an absolute URL with an IANA-registered scheme).
  • In addition to being an argument to Url::fromUri(), URIs within any of these schemes can also be the value of a link field's uri property. Potentially, in the future, these URIs can also be stored as configuration values (such as within a View), though no core configuration structures have yet been converted to do so (Views still stores paths, not URIs).
  • The schemes entity, route, and base were named based on pre-existing terminology used throughout Drupal (entities, routes, and base_path()/$base_url).
  • However, user-path is proving to be a problematic name, because:
    • URIs in this scheme are not identifiers of things about a user (i.e., they are not only for user profile pages). Rather, they are strings supplied by a user (e.g., when a user enters a path/URL into a link field) for linking to anything.
    • In contradiction to the above, some URIs in this scheme are not supplied by a user. For example, tests that create mock link field values, and install profiles that create real entities with pre-populated link field values (e.g., standard.install creates a couple Shortcut entities). Maybe these exceptions can be explained away by arguing that tests are mocking user input and that install profiles create content on behalf of a user, but another exception is the RssFields Views plugin, which when the guid_field_is_permalink option is used, the plugin generates a URL from a GUID, and GUIDs are system-generated, not user-entered.

Proposed resolution

  • Provide a Url::fromUserInput() wrapper method to handle the most common cases, where we really are dealing with something that might be user input. This makes sense to do regardless of if we also do the rest of the proposal, so is split out into #2426181: Add a Url::fromUserInput() wrapper method for generating URLs from user-entered paths.
  • Rename the scheme from user-path to internal to avoid the confusion of "user-path" being misinterpreted as being about a user and to avoid confusion when the scheme is used for the cases above where we are not necessarily dealing with user input.

Concerns raised about the scheme rename part of the proposal:

  • Drupal has a history of using the term "internal path" to refer to only Drupal-routed paths (grep HEAD for "internal path" to see how widespread that still is), whereas the proposed internal scheme can be used for any URL within the same website, whether handled by Drupal, another application, or a static file. A counter-argument to this concern is that Drupal's history has been an incorrect usage of the word "internal" in relation to URLs and that the conventional meaning of an "internal URL" is in relation to the site, not to the software used by the site. Furthermore, Url::isExternal() and LinkItemInterface::LINK_INTERNAL are based on this conventional definition of "internal" rather than on Drupal's legacy usage of "internal path".
  • There is some code that would be referring to the internal scheme directly, even when dealing with user input, because the Url::fromUserInput() method is only for constructing a $url object, but some code needs to work with direct URI strings instead (e.g., LinkWidget). However, it's not clear whether there's anything wrong with that, and if there is, we can find a solution to it (e.g., to make Url::fromUserInput($user_input)->toUriString() return the desired URI).

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Task; there is no functional bug.
Prioritized changes The main goal of this issue is correcting a misleading scheme name introduced in a previous critical issue since the last beta.  As a followup to a critical, it is a prioritized change.
Disruption Disruptive for core, contributed and custom modules, and possibly themes (?) because it will require both a BC break in code that deals with paths from user input, and a break to stored data (everything that stores a user-path URI will need to be updated).

Remaining tasks

User interface changes

No.

API changes

Yes.

Comments

webchick’s picture

FWIW, I have no idea why we can't just use path: here. It's what we called these things in D6/D7 (see screenshot of old UI at #2416987: Fix UI regression in the menu link form), it's shorter to type, and it was the other of the options catch approved in #2405551-86: Add a method to support UIs where users enter paths instead of route names and other valid use cases. Anything with "user" in it doesn't really make sense because, as evidenced by standard.install, these are not always user-entered paths at all.

wim leers’s picture

#1: because "path" as a URI scheme makes no sense, since "path" is also actually a component of every URI. So that'd mean we'd have to say funny things like get the path of that path URI :)

webchick’s picture

Fair enough, but does the fact that a confusing sentence might come up once in awhile outweigh the fact that this is going to totally confuse every developer who has to programmatically create a "hard-link"? And, given your -1 on path:, how about relative:?

jibran’s picture

How about base-uri: or base-url:?

cafuego’s picture

root: ? Less typing, and these paths are all relative from the drupal root, as far as I can tell. I also don't think root is used anywhere else yet.

yched’s picture

raw: ? unrouted: ?

almaudoh’s picture

drupal:?? Had to say it :P

xjm’s picture

So keep in mind that we already have base: for, e.g., base:robots.txt in code. The point of this one is to denote user input. :)

xjm’s picture

@webchick:

Anything with "user" in it doesn't really make sense because, as evidenced by standard.install, these are not always user-entered paths at all.

All of the (very few) instances in core are actually for user-entered input stored in the database, or test coverage for this:

core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php:   * Gets the URI without the 'user-path:' scheme, for display while editing.
core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php:          $value['uri'] = 'user-path:' . $value['uri'];
core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php:   * Override the '%url' message parameter, to ensure that 'user-path:' URIs
core/modules/shortcut/src/Controller/ShortcutSetController.php:          'uri' => 'user-path:' . $link,
core/modules/shortcut/src/Tests/ShortcutLinksTest.php:      $this->assertTrue(in_array('user-path:' . $test_path, $paths), 'Shortcut created: ' . $test_path);
core/modules/shortcut/src/Tests/ShortcutLinksTest.php:    $this->assertTrue(in_array('user-path:' . $new_link_path, $paths), 'Shortcut path changed: ' . $new_link_path);
core/modules/shortcut/src/Tests/ShortcutTestBase.php:          'uri' => 'user-path:node/add',
core/modules/shortcut/src/Tests/ShortcutTestBase.php:          'uri' => 'user-path:admin/content',
core/profiles/standard/standard.install:    'link' => array('uri' => 'user-path:node/add'),
core/profiles/standard/standard.install:    'link' => array('uri' => 'user-path:admin/content'),
core/tests/Drupal/Tests/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidatorTest.php:    $data[] = [$this->getMock('Drupal\Core\TypedData\Type\UriInterface'), 'user-path:', TRUE];

The two instances in standard.install are defaults for shortcuts, because we don't support the rest through the UI yet, but Wim is about to open an issue for this.

xjm’s picture

Issue summary: View changes
xjm’s picture

Issue summary: View changes

Updated the summary to try to clarify the purpose of the scheme.

xjm’s picture

Issue summary: View changes
xjm’s picture

Issue summary: View changes
berdir’s picture

Isn't changing this... problematic? We either need to do it before the upgrade path or provide update functions for it?

effulgentsia’s picture

Issue tags: +D8 upgrade path

Re #14, the issue summary says this is timeboxed to the next beta. But also adding the "D8 upgrade path" tag for extra clarity.

berdir’s picture

@effulgentsia: Thanks, did not see that.

I'm quite confused now, because I really thought that I wrote a comment below already a few minutes ago, wondering if I posted that into a wrong issue somewhere ;)

My personal opinion is to stick with user-path, unless we are really convinced that we have a considerably better name than user-path, which would solve DX problems that we would have with user-path.

Many contrib modules track HEAD, not beta versions (Testbot can't target beta releases, for one reason), I've already updated a considerable amount of contribs to use base:, user-path: and so on over the weekend, as I'm using them for my project. Also, code would be relatively easy to fix, just a search and replace, but I'd rather not break existing installations unless we have a good reason to do so.

cafuego’s picture

My first thought was 'node/add' has nothing to do with users, why would that exist on their profile? It's confusing and shouldn't be.

catch’s picture

What about 'stored-path'?

effulgentsia’s picture

Some thoughts:

  1. I don't like path, relative, or any combination that contains only those words or their synonyms, because those words have specific meanings already defined in RFC 3986. As a scheme name, they tell you nothing. A path to what? Relative to what? The purpose of a scheme name is to help answer those questions, so basing a scheme name on those words is highly circular.
  2. #2405551-17: Add a method to support UIs where users enter paths instead of route names and other valid use cases proposed renaming base to unrouted and then renaming user-path to routed. That proposal was prior to us deciding to make user-path have the logic of checking for a route first, then falling back to a non-route, so this proposal would need to be updated to rename user-path to maybe-routed, which I think is a bit icky, so -1.
  3. I think the most fundamental objection to user-path is that it doesn't handle (in terms of accuracy of the name) the use cases #5 and #6 from the issue summary of #2405551: Add a method to support UIs where users enter paths instead of route names and other valid use cases. David_Rothstein has argued that these use cases should be treated as legitimate, while pwolanin has argued they should not be.
  4. If we want to legitimize those use cases (for custom modules, not for core, see also #2416843: Decide if a Url::fromPath() method and/or a Url::fromUri() scheme other than 'base' or 'user-path' is wanted to support contrib/custom modules), I'd like to suggest site. I think that is the most accurate semantics, because the name base was chosen to correspond to the definition of "base URI", which the specification requires to be independent of the path that follows. However, "site" is not defined by that specification, and IMO would just imply "something that is on this site", for which our current logic of user-path is fully suitable. Additionally, I also think of "base" as connoting a meaning of "depends only on where Drupal is installed" and "site" as connoting a meaning of "depends on the site's configuration", both of those connotations being accurate aspects of the corresponding schemes.
  5. Even if we don't want to legitimize those use-cases, I think site is a decent name. I know pwolanin wanted the name to make very clear that it should only be used when dealing with user input, but I also respect David's perspective in #2405551-70: Add a method to support UIs where users enter paths instead of route names and other valid use cases that we don't always need to embed the proper use case of something into its name.
xjm’s picture

Hmm, #19 for me doesn't cover the most important thing about the scheme, which is that it's for user input only. I disagree with proposals that allow it for non-user-input. I also don't really agree with point 5. I can't imagine seeing site: and understanding or remembering how it's different from base:. It doesn't tell me that it could be routed, unrouted, tokenized, unsanitized, garbage...

xjm’s picture

With the current direction of #2417459: Provide internal API for special schemes and thin public wrappers for user input and non-routed URLs, I could see fromUserCreatedPath() or fromRawInputPath() or something like that. With method names, we lose the issue of verbosity and can be clearer about the purpose of the scheme, and avoid the confusion about paths to or for users. The scheme string itself becomes less critical.

Edit: I'm still a fan of user-input: for the scheme itself as it's the most explicit.

effulgentsia’s picture

If the decision gets made to keep the scheme name having the word user in it, then some suggestions to address #17:

- user-input
- user-entered
- user-provided
- user-specified

Not sure if those are improvements at all, or even if they are, if they're sufficient improvements to overcome #16. A problem with those first two is that what we store might not be exactly what the user typed. For example, maybe the user started with a leading slash, but we store without the leading slash. Even if we end up doing #2417647: Add leading slash to paths within 'user-path:' URIs, to allow 'user-path:' URIs to point to the <none> route, maybe some other widget will want to come along and not require users to enter a leading slash. I don't think we should change our storage model every time we want to change UX, so we should assume that some level of normalization can happen on input.

Anything with "user" in it doesn't really make sense because, as evidenced by standard.install, these are not always user-entered paths at all.

If we keep user-SOMETHING in the name, then we may want a separate scheme for the few use cases like an install profile installing an initial value that could then be edited by the user. Since technically, those initial values themselves are not input, entered, provided, or specified by the user. But that's a solvable problem that we can discuss further in #2416843: Decide if a Url::fromPath() method and/or a Url::fromUri() scheme other than 'base' or 'user-path' is wanted to support contrib/custom modules.

catch’s picture

hen we may want a separate scheme for the few use cases like an install profile installing an initial value that could then be edited by the user. Since technically, those initial values themselves are not input, entered, provided, or specified by the user.

This is why I suggested 'stored'. The main thing that distinguishes this is that it's stored (in either configuration or content entities usually). When we're using it for shortcuts, 99.9% of the time the user isn't actually entering a path in a form at all either.

xjm’s picture

As far as I understand, shortcut is an interim state. At least, that's what I've heard several times from those working on it.

webchick’s picture

Given the next beta is February 25, a week prior to that seems like a good deadline for this discussion, to give us enough time to roll/re-roll a patch (if applicable).

Also adding "Needs issue summary update" because I don't think any of the discussion has been captured there yet.

webchick’s picture

If #2417459: Provide internal API for special schemes and thin public wrappers for user input and non-routed URLs ends up happening (which it appears there is growing support for), I wonder how important it is that we retain the "user" part of this scheme name, given that it is our sincere hope that 99% of developers will never deal in writing these schemes out manually, in favour of using the method wrappers (which would have "user" in the name).

That would open back up options such as path: or relative: or some other straight-forward, plain-English description, since the primary reason to change this scheme name is the confusion it's causing people due to the fact that it's used for more than just user-input.

effulgentsia’s picture

the confusion it's causing people due to the fact that it's used for more than just user-input

I wouldn't characterize it as confusion, but disagreement. There are some people arguing that it should ONLY be used for user input, and others wanting the same functionality available for non-user-input.

#23's suggestion of 'stored' is interesting, in that it covers things that are stored in config or content, but that might have been set by code (e.g., an install profile or Shortcut's star icon). But I also wonder if we should store those cases with a different scheme, such as route: for the case of Shortcut's star icon.

catch’s picture

@effulgentsia I don't think it matters whether something in config or content was created by actual user input or via the API (or between shortcuts star icon and the shortcut admin form) - the end result is going to be the same. If I saw a different scheme I'd expect it to be treated differently rather than an alias.

effulgentsia’s picture

I've been thinking about stored as a scheme name, and although it might be 99% accurate (its main use case is for internal links, defined by path, that need to be stored, and as a result, whether it's routed or not, and if so, which route it resolves to, can change between when it's written and when it's read), it just doesn't feel right to me. I'm open to it if others like it, but on a gut level, I'm not crazy about it.

I tried to rethink what the base and user-path schemes represent, and whether it's possible to find names for both that reuse common terminology for how people think about links.

I think that the most important aspect of the base scheme is that it will return a $url whose isExternal() = FALSE and isRouted() = FALSE. And I think the most important aspect of the user-path scheme is that it will return a $url whose isExternal() = FALSE and whose isRouted() might be either TRUE or FALSE.

With that in mind, what if we rename base to unrouted and rename user-path to internal?

Hmm, #19 for me doesn't cover the most important thing about the scheme, which is that it's for user input only.

So per #27, I think this is the fundamental disagreement in this issue. I think what's most important about the scheme is that it's for links to something that is internal to the site but may or may not be handled by Drupal (e.g., /blog can be a Drupal route or a subfolder in which Wordpress is installed, but in either case it's still part of the same website). And that user input is perhaps the only legitimate use case for such links, but that's secondary. However, I also understand the perspective that the user inputtedness of it is very important and that importance needs to be reflected somehow. Would this desire be sufficiently addressed by #2417459: Provide internal API for special schemes and thin public wrappers for user input and non-routed URLs's addition of a Url::fromUserInput() method, even if what the method did was create a $url whose URI is in the internal scheme?

I don't think it matters whether something in config or content was created by actual user input or via the API

Ok, so with the above proposal, code that deals with user input can call Url::fromUserInput(), and code like an install profile that creates path-based menu/shortcut links can write out 'uri' => 'internal:/node/add' directly (or use a constant for 'internal'), so as not to call fromUserInput() on something that isn't user input.

webchick’s picture

I like internal: quite a lot, and I think the Url::fromUserInput() in the public API helps people do the right behaviour.

unrouted: sounds like technical gobbeldygook, but at least is much more clear exactly what it means than base. Though I still would prefer to merge these and some smart code behind the scenes do $this->isRouted = $this->isThisARoute($path); to determine what $isRouted should be set to programmatically versus having a human have to do the distinction. Because once again to a "lay person" both /README.txt and /node/add are "internal" links.

wim leers’s picture

I think that the most important aspect of the base scheme is that it will return a $url whose isExternal() = FALSE and isRouted() = FALSE. And I think the most important aspect of the user-path scheme is that it will return a $url whose isExternal() = FALSE and whose isRouted() might be either TRUE or FALSE.
[…]
With that in mind, what if we rename base to unrouted and rename user-path to internal?

Funny… in trying to think of simplifications for the "many methods" problems at #2417459: Provide internal API for special schemes and thin public wrappers for user input and non-routed URLs, I thought: What if we added a InternalUrl class? That could deal with user-path: and entity: URIs. And an ExternalUrl class could deal with base: and http: etc URIs.

In that light, this proposal makes a lot of sense to me. entity: is a special kind (a subset) of internal link, which is also semantically/logically consistent with an internal: URI scheme.

It's also wholly consistent with Drupal's long-standing need for "internal links" that keep working after migrating from dev to staging. I've long wanted to add a text format filter that transforms internal URIs to resolved URLs. Seeing <a href="internal:/contact">Contact us</a> to hear more! or Read more <a href="entity:taxonomy_term/5">about llamas</a> in there is completely natural.

Finally, user-path: stresses the fact that it's a user-entered path… which is true, but OTOH any such URI has actually already gone through validation. So the danger we associate with "user input OMG OMG" actually is no longer there; the validation has already taken care of that. Which is another point in favor of internal: IMO, especially together with a Url::fromUserInput() method (or, if my proposal to simplify the Url::from*() land is applied, perhaps even InternalUrl::fromUserInput()).

EDIT: I've always favored unrouted: over base: for its absolute clarity and its conveying of exactly what it is. It's others that need to be convinced.

webchick’s picture

Issue summary: View changes
Issue tags: -Needs issue summary update

Updating the issue summary to reflect current convergence, and also to remove the list of ones we're not going to do (curious people can just read the issue).

webchick’s picture

Title: Bikeshed the user-path: scheme » Rename user-path: scheme to internal:

And a more focused title.

webchick’s picture

Also, effulgentsia pointed out that user-path:/internal: already works in the way I described in #30, so in that case, spun out #2422995: Remove the base: scheme in favour of user-path:/internal:.

xjm’s picture

Component: menu system » routing system
Assigned: Unassigned » xjm

I think internal: / fromUserInput() also makes sense. I'll split that bit out from #2417459: Provide internal API for special schemes and thin public wrappers for user input and non-routed URLs and post a starting patch here.

xjm’s picture

Assigned: xjm » Unassigned
Status: Active » Needs review
Issue tags: +DX (Developer Experience)
StatusFileSize
new44.95 KB

Initial patch. Renames the scheme, adds fromUserInput, and adds the internal constant. I'll post a few notes with Dreditor in a subsequent comment.

xjm’s picture

  1. +++ b/core/lib/Drupal/Core/Form/ConfirmFormHelper.php
    @@ -34,7 +34,7 @@ public static function buildCancelLink(ConfirmFormInterface $form, Request $requ
    -      $url = Url::fromUri('user-path:/' . $options['path'], $options);
    +      $url = Url::fromUserInput('/' . $options['path'], $options);
    
    +++ b/core/modules/field_ui/src/FieldUI.php
    @@ -61,7 +61,7 @@ public static function getNextDestination(array $destinations) {
           // Redirect to any given path within the same domain.
    -      $next_destination = Url::fromUri('user-path:/' . $options['path']);
    +      $next_destination = Url::fromUserInput('/' . $options['path']);
    

    Should we change the expectation for the destination parameter to always include a leading slash? (Would be a followup.)

  2. +++ b/core/lib/Drupal/Core/Url.php
    @@ -190,6 +202,41 @@ public static function fromRouteMatch(RouteMatchInterface $route_match) {
    +  public static function fromUserInput($path, $options = []) {
    

    Will add tests for this once I see what happens with the patch itself.

  3. +++ b/core/lib/Drupal/Core/Url.php
    @@ -317,46 +365,46 @@ protected static function fromEntityUri(array $uri_parts, array $options, $uri)
    -   * Creates a new Url object for 'user-path:' URIs.
    +   * Creates a new Url object for 'internal:' URIs.
    ...
    +  protected static function fromInternalUri(array $uri_parts, array $options) {
    ...
    -    // only accept/contain paths without a leading slash, unlike 'user-path:'
    

    We should probably move some of the (lengthy) docs for this to the public method, but for now I've just replaced the scheme name.

  4. +++ b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php
    @@ -210,7 +210,7 @@ public function viewElements(FieldItemListInterface $items) {
               // @todo Does RDF need a URL rather than an internal URI here?
               // @see \Drupal\rdf\Tests\Field\LinkFieldRdfaTest.
    -          $content = str_replace('user-path:/', '', $item->uri);
    +          $content = str_replace(Url::SCHEME_INTERNAL . '/', '', $item->uri);
    

    In addition to the @todo, feels like we shold not be doing this string replace here. Additionally, shouldn't the path be displayed with the leading slash, in order to be aligned with the expectations set in #2417647: Add leading slash to paths within 'user-path:' URIs, to allow 'user-path:' URIs to point to the <none> route and for the user interface? Would be a followup.

  5. +++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
    @@ -51,11 +51,11 @@ public static function defaultSettings() {
         $scheme = parse_url($uri, PHP_URL_SCHEME);
    -    if ($scheme === 'user-path') {
    +    if ($scheme === Url::SCHEME_INTERNAL) {
    
    +++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
    @@ -186,7 +187,7 @@ public static function preCreate(EntityStorageInterface $storage, array &$values
    -    if (parse_url($this->link->uri, PHP_URL_SCHEME) === 'user-path') {
    +    if (parse_url($this->link->uri, PHP_URL_SCHEME) === Url::SCHEME_INTERNAL) {
    

    I think we could add an API method for this check; it happens in several places.

  6. +++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
    @@ -77,7 +77,7 @@ protected static function getUriAsDisplayableString($uri) {
       /**
        * Gets the user-entered string as a URI.
        *
    -   * Schemeless URIs are treated as 'user-path:' URIs.
    +   * Schemeless URIs are treated as 'internal:' URIs.
    ...
    @@ -115,7 +115,7 @@ protected static function getUserEnteredStringAsUri($string) {
    
    @@ -115,7 +115,7 @@ protected static function getUserEnteredStringAsUri($string) {
    -        return 'user-path:' . $string;
    +        return Url::SCHEME_INTERNAL . ':/' . $string;
    

    We might want to look into refactoring this method. Maybe this is going to be fixed up in #2418017: Implement autocomplete UI for the link widget?

  7. +++ b/core/modules/menu_link_content/menu_link_content.module
    @@ -45,7 +46,7 @@ function menu_link_content_path_insert($path) {
    - * Helper function to update plugin definition using user-path scheme.
    + * Helper function to update plugin definition using internal scheme.
    ...
    @@ -58,7 +59,7 @@ function _menu_link_content_update_path_alias($path) {
    
    @@ -58,7 +59,7 @@ function _menu_link_content_update_path_alias($path) {
    -    ->loadByProperties(['link__uri' => 'user-path:/' . $path]);
    +    ->loadByProperties(['link__uri' => Url::SCHEME_INTERNAL .'/' . $path]);
    

    This helper function also implies that something maybe should be refactored (in a followup).

  8. +++ b/core/modules/menu_link_content/src/Tests/LinksTest.php
    @@ -67,14 +67,14 @@ function createLinkHierarchy($module = 'menu_test') {
    -      'link' => ['uri' => 'user-path:/menu-test/hierarchy/parent'],
    +      'link' => ['uri' => 'internal:/menu-test/hierarchy/parent'],
    

    Note: In tests, I've deliberately used the hardcoded string, rather than the constant. This is not an inconsistency; it probably makes sense to hardcode things in related tests to ensure we're testing the right things. That said, I didn't closely examine each test to see what was appropriate in each case.

  9. +++ b/core/modules/shortcut/src/Controller/ShortcutSetController.php
    @@ -65,7 +65,7 @@ public function addShortcutLinkInline(ShortcutSetInterface $shortcut_set, Reques
    -          'uri' => 'user-path:/' . $link,
    +          'uri' => 'internal:/' . $link,
    
    +++ b/core/profiles/standard/standard.install
    @@ -58,7 +58,7 @@ function standard_install() {
    -    'link' => array('uri' => 'user-path:/node/add'),
    +    'link' => array('uri' => 'internal:/node/add'),
    
    @@ -66,7 +66,7 @@ function standard_install() {
    -    'link' => array('uri' => 'user-path:/admin/content'),
    +    'link' => array('uri' => 'internal:/admin/content'),
    

    Do we have that issue for fixing shortcut somewhere?

  10. +++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
    @@ -1248,7 +1248,9 @@ public function renderText($alter) {
    +        // @todo Convert Views to expect a leading slash for path
    +        //   configurations. Needs followup issue.
    +        $more_link = \Drupal::l($more_link_text, CoreUrl::fromUserInput('/' . $more_link_path), array('attributes' => array('class' => array('views-more-link'))));
    

    Views should probably expect and display leading slashes as well (in a followup).

wim leers’s picture

I think we could add an API method for this check; it happens in several places.

If it's just for the scheme checking: PHP already provides an API for it (parse_url()), which is what we choose to use. No need to abstract this away. At least, that's what effulgentsia, pwolanin and I thought at the NJ sprint.

Do we have that issue for fixing shortcut somewhere?

What do you mean?

Status: Needs review » Needs work

The last submitted patch, 36: internal-2417567-36.patch, failed testing.

xjm’s picture

Do we have that issue for fixing shortcut somewhere?

What do you mean?

Several times, we've stated that shortcut is in an interim state where it doesn't support all the things, and that's why it has (edit!) user-path: all over it. However, I can't find the issue that's supposed to fix it.

xjm’s picture

Assigned: Unassigned » xjm
Status: Needs work » Needs review
StatusFileSize
new45.51 KB
new573 bytes

Migrate oopsie... (I still don't get those being config entities btw.)

Looking into the other fails.

Status: Needs review » Needs work

The last submitted patch, 41: interdiff.patch, failed testing.

The last submitted patch, 41: internal-2417567-41.patch, failed testing.

xjm’s picture

Status: Needs work » Needs review
StatusFileSize
new45.51 KB
new1.37 KB

Should fix the fails (I think).

Status: Needs review » Needs work

The last submitted patch, 44: internal-2417567-2417567-43.patch, failed testing.

xjm’s picture

Status: Needs work » Needs review
StatusFileSize
new45.51 KB
new669 bytes

Status: Needs review » Needs work

The last submitted patch, 46: internal-2417567-46.patch, failed testing.

xjm’s picture

Status: Needs work » Needs review

One more.

xjm’s picture

StatusFileSize
new45.51 KB
new814 bytes

...upload failure. DrupalCon wifi--

tim.plunkett’s picture

+++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
@@ -51,11 +51,11 @@ public static function defaultSettings() {
-      //   remove the ability to enter '<front>' or '<none>', we'll expect '/'
+      //   remove the ability to enter '<front>' or '<none>', well expect '/'

well change back to we'll

Otherwise, I think this patch is great.

Status: Needs review » Needs work

The last submitted patch, 49: internal-2417567-47.patch, failed testing.

xjm’s picture

Needs update for #2409209: Replace all _url() calls beside the one in _l() now. The Drop is always moving, etc.

well change back to we'll

lol... I guess PHPstorm tried to "fix" my quote delimitation? We shouldn't be using contractions anyway.

xjm’s picture

Assigned: xjm » Unassigned
Status: Needs work » Needs review
StatusFileSize
new49.91 KB
new5.24 KB
xjm’s picture

Wait a second, I didn't even make any changes to the line in #50... overhelpful IDE--.

Not bothering to revert the out-of-scope line for now.

xjm’s picture

Assigned: Unassigned » xjm
Issue tags: +Needs tests

Oh right.

dawehner’s picture

I'm sorry but I still think that internal has less semantic than user-path had.
IMHO its a bad assumption to not use user-path because "it went through validation", ... we talk about an API function here, there is noone assuring that every user
string went through validation, nor does it make sense to change the behaviour after validation.

effulgentsia’s picture

I'm sorry but I still think that internal has less semantic than user-path had.

And related comment from #2422995-19: Remove the base: scheme in favour of user-path:/internal::

For me at least internal:// is really confusing, because I would have 100% assumed that its a route controlled by Drupal

I understand the above sentiment, especially since in Drupal we have a history of saying "internal path" to mean "a Drupal-controlled path", but I think our history of using language that is inconsistent with the rest of the world should not count against us moving towards semantics that are consistent with the rest of the world.

If you have your Drupal installation in http://example.com, and a Wordpress installation in http://example.com/blog, then regardless of whether a user types "/blog" or whether an install profile does an entity_create('menu_link_content', array(..., 'uri' => 'SOME_SCHEME_NAME:/blog')), then I think it is simply incorrect for anyone to think that that is not an "internal" link. The "internal" vs. "external" terminology for links/URLs is entirely about "internal to the website", not about which piece of software processes the request. Drupal's history of equating "internal" to "internal to Drupal" is an artifact of its history of being monolithic, but elsewhere throughout Drupal 8, we've gotten off the island, and we should apply the same spirit here.

However, while a user typing "/blog" can be rightly classified as a "user path", an install profile doing the above entity creation can't be (IMO), so therefore, I think internal is more semantically correct and clear than user-path, once you make the jump to not thinking that Drupal is the only piece of software that is "internal" to your website.

xjm’s picture

Issue tags: -Needs tests
StatusFileSize
new52.29 KB
new5.09 KB
new52.29 KB
new5.09 KB
+++ b/core/modules/views/views.theme.inc
@@ -405,7 +406,7 @@ function template_preprocess_views_view_summary_unformatted(&$variables) {
-      $url = Url::fromUri('user-path:/' . $base_path);
+      $url = Url::fromUri('/' . $base_path);

I broke this (it will throw an exception) but nothing failed. Fixed that bug in the attached patch but did not try to add test coverage (brrrr, views.theme.inc).

Also added the tests, fixed some test naming/docs, and fixed that silly apostrophe thing.

The last submitted patch, 58: internal-2417567-57.patch, failed testing.

xjm’s picture

Assigned: xjm » Unassigned

So good you get it twice.

xjm’s picture

IMHO its a bad assumption to not use user-path because "it went through validation", ...

From my perspective, the reason not to call it user-path is that it's not a path to or for a user.

xjm’s picture

Title: Rename user-path: scheme to internal: » Rename user-path: scheme to internal: and provide fromUserInput() wrapper method.
wim leers’s picture

Several times, we've stated that shortcut is in an interim state where it doesn't support all the things

I really don't know what this refers to. Shortcut now uses the link field and link widget. In terms of being able to store links, I really don't know what's missing.

However, while a user typing "/blog" can be rightly classified as a "user path", an install profile doing the above entity creation can't be (IMO) […]

I think there's a simple justification in this case: the install profile creates this link on behalf of the user.

tim.plunkett’s picture

I think that every name we pick is going to have some confusion inherent in it.
At this point, I think all that we can do is pick the least confusing name, the one that needs the least explaining.

Because once the intention is explained, you don't need to relearn it each time.

So let's focus on the most easily understood name.

effulgentsia’s picture

StatusFileSize
new56.21 KB

Reroll + some manual conflict resolution

effulgentsia’s picture

effulgentsia’s picture

StatusFileSize
new9.85 KB

So let's focus on the most easily understood name.

Let's keep in mind that wherever code is dealing directly with user input, it can call Url::fromUserInput(). So, the attached patch is just the hunks that do not do that, and instead deal with the scheme name directly. I think these are the hunks we should evaluate with respect to which scheme name is most understandable. I also omitted the Url class itself, since APIs should be evaluated based on how callers are impacted rather than how the implementation is impacted.

xjm’s picture

Removed the constant. Let's defer that to #2417459: Provide internal API for special schemes and thin public wrappers for user input and non-routed URLs.

If we are changing all these lines anyway, it's not clear to me why we would split this into separate issues and change them again. I'd rather re-scope this issue to deal with internal (as we have) and deal with base: etc. there (as we already are).

effulgentsia’s picture

StatusFileSize
new55.7 KB

Just a reroll.

effulgentsia’s picture

Maybe what's best to do here is baby steps. In order to separate where we are dealing with actual user input from other usages of the scheme, I opened #2426181: Add a Url::fromUserInput() wrapper method for generating URLs from user-entered paths as a child issue. Maybe let's work on getting that in first? Then we can discuss the remaining hunks here with less noise.

effulgentsia’s picture

I think that every name we pick is going to have some confusion inherent in it.
At this point, I think all that we can do is pick the least confusing name, the one that needs the least explaining.

Ok, so what I'd like to point out about all the hunks in #67 is that they're all dealing with the 'uri' value of a link field. Because all of HEAD's other usages of the 'user-path' scheme can use the Url::fromUserInput() wrapper method that's in #2426181: Add a Url::fromUserInput() wrapper method for generating URLs from user-entered paths. But what's left in #67 is where we need to work with a URI string rather than a $url object, and at least so far in HEAD, the only place we do that is the link field.

And when it comes to the link field, we already have a LinkItemInterface::LINK_INTERNAL constant and a LinkItem::fieldSettingsForm() implementation that exposes the terminology "internal links" and "external links" to the UI for configuring that field.

So, I think naming the scheme "internal" wouldn't require much explanation: it means the same thing as what the link field already means in the above.

wim leers’s picture

What do we need here to move forward again?

mpdonadio’s picture

Assigned: Unassigned » mpdonadio
Status: Needs review » Needs work
Issue tags: +Needs reroll

The patch needs a reroll. I'll do it shortly.

However, I think the argument in #71 is good, especially the parallel to the terminology in the link field, and that moving forward with 'internal:' is a good idea.

mpdonadio’s picture

Assigned: mpdonadio » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new55.81 KB

Minor manual merge in the docblock for Url::fromInternalUri() b/c of a change from #2423579: Url::fromUrl('user-path:/') should throw an exception when a path component without a slash is given.

Status: Needs review » Needs work

The last submitted patch, 74: rename_user_path-2417567-74.patch, failed testing.

mpdonadio’s picture

Status: Needs work » Needs review
StatusFileSize
new56.08 KB
new498 bytes

Forgot to update a test that got added. Passes locally now.

hussainweb’s picture

I am wondering that with the scheme as internal:, won't it make more sense to call the method as fromInternal() or fromInternalPath()? I see the method is introduced here (or in #2426181: Add a Url::fromUserInput() wrapper method for generating URLs from user-entered paths) and we could reconsider renaming it as we are also renaming user-path.

I re-read the comment in #29 and think that as internal makes more sense than user-path, fromInternalPath() also could give more clarity than fromUserInput().

Also, I see that parts of this patch are also in #2426181-11: Add a Url::fromUserInput() wrapper method for generating URLs from user-entered paths. Should this be postponed until then? (I know this deadline is today).

effulgentsia’s picture

Issue summary: View changes

I completely rewrote the summary. Hope it's helpful. Feel free to edit if not.

won't it make more sense to call the method as fromInternal() or fromInternalPath()?

I don't think so. The point of the method is to only use it for user input, and to be clear that that's its only purpose. Whereas the more generic scheme name is to also cover the cases when it's not user input. In the future, fromUserInput() might do more than just be a wrapper around the generic scheme. For example, maybe it will perform additional validation or set a special key in $options to maintain a flag that it's from user input.

Also, I see that parts of this patch are also in #2426181-11: Add a Url::fromUserInput() wrapper method for generating URLs from user-entered paths. Should this be postponed until then?

I think it makes sense to not commit this issue until after that one. But I think it's good to keep the status of this as not postponed, because discussion and reviews of the non-overlapping parts can be happening in parallel.

I know this deadline is today

According to #25, today's deadline was just to reach a decision, and that we still have a few more days to get the patch to RTBC and committed.

effulgentsia’s picture

Issue summary: View changes

Fixed an example in the summary.

hussainweb’s picture

StatusFileSize
new1.85 KB
new57.39 KB

I just caught a few more references to user-path: and changed it to internal:.

xjm’s picture

Assigned: Unassigned » xjm

Thanks @hussainweb! We should change those method names too. EDIT: That is, change the names of test methods that test the user-path scheme to not be testFooUserPathBar(). However, I think it would make sense to only roll this patch on top of #2426181: Add a Url::fromUserInput() wrapper method for generating URLs from user-entered paths (which I am updating now). I'll reroll this on top of that once that's posted.

xjm’s picture

Assigned: xjm » Unassigned
StatusFileSize
new44.64 KB
new61.03 KB
new9.46 KB

Rerolled on top of #2426181: Add a Url::fromUserInput() wrapper method for generating URLs from user-entered paths. The -do-not-test.patch includes only the changes that aren't included there. The interdiff, similarly, includes changes that aren't included there. Renamed the relevant test methods, a few missed things, etc., and reverted a couple out-of-scope changes and use statements that were no longer needed.

xjm’s picture

xjm’s picture

Issue summary: View changes
Issue tags: +Needs change record updates

Beta eval. Also presumably there's a CR out there somewhere that would need an update.

xjm’s picture

Issue summary: View changes

One of these days I will fill out the template without leaving a --> in.

xjm’s picture

Issue summary: View changes
xjm’s picture

Title: Rename user-path: scheme to internal: and provide fromUserInput() wrapper method. » Rename user-path: scheme to internal:
StatusFileSize
new44.61 KB

fromUserInput() is in now. No additional instances of grep -r "user-path" nor grep -ri "userpath", except for the one in PathBasedBreadcrumbBuilderTest that is actually a about path to a user, not an internal URI. ;)

NR!

xjm’s picture

https://www.drupal.org/node/2417421 somehow never got published, but that's the one we'll want to update for this. Added it here.

xjm’s picture

Hm actually, that change record never got finished -- some of the info on it is incorrect. But that's out of scope here.

effulgentsia’s picture

Status: Needs review » Reviewed & tested by the community

Patch looks great to me. Just does what the issue title says, so RTBC. Committers: please let this sit at RTBC for 24 hours or so to give anyone who might still disagree with this issue a chance to say so.

+++ b/core/lib/Drupal/Core/Url.php
-   * Note: the user-path: scheme should be avoided except when processing actual
+   * Note: the internal: scheme should be avoided except when processing actual
    * user input that may or may not correspond to a Drupal route. Normally use
    * Url::fromRoute() for code linking to any any Drupal page.

I think we'll want to change this doc, but that can be a followup, because it'll probably take us some time to come to consensus on what it should say.

xjm’s picture

@effulgentsia, yeah I forgot to mention, but there's a lot of docs work that needs to be done at some point that is out of scope here. #2417459: Provide internal API for special schemes and thin public wrappers for user input and non-routed URLs includes a bunch of work in that area, though it's possible we might want to split the scope there, too.

mpdonadio’s picture

Are there any in-progress issues/patches that introduce new user-path: usages that will need to be rerolled after this?

xjm’s picture

Issue summary: View changes
xjm’s picture

@mpdonadio, probably a number of things in the queue will need rerolls, but nothing outstanding from #2407505: [meta] Finalize the menu links (and other user-entered paths) system to my knowledge. #2417459: Provide internal API for special schemes and thin public wrappers for user input and non-routed URLs is stale now, but in the good way.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committing in the last minute before the beta release freeze so this is in the next beta. Committed 368cf51 and pushed to 8.0.x. Thanks!

Thanks for adding the beta evaluation to the issue summary.

  • alexpott committed 368cf51 on 8.0.x
    Issue #2417567 by xjm, effulgentsia, mpdonadio, hussainweb: Rename user-...
pwolanin’s picture

I'm sad to see this go in - I think "internal:" is totally misleading.

dawehner’s picture

What peter says. For me internal:motivates people to not use route:, even if they would know it.
User-path had more semanticness for me.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.