Path aliases are not available in hook_post_update_NAME

Created on 9 January 2023, almost 2 years ago
Updated 13 March 2023, over 1 year ago

Problem/Motivation

According to the docs for hook_post_update_NAME, "Drupal is already fully repaired so you can use any API as you wish". However, when I load a node to get its URL, it always returns the internal path (e.g., /node/123) not the path alias.

I believe this is due to the path alias outbound processor being removed from the updates process in \Drupal\Core\Update\UpdateServiceProvider::alter

Since the docs state that I can use "any API", should I expect the URL generator to return the internal path OR the alias in hook_post_update_NAME?

Steps to reproduce

  1. Create a node with a path alias
  2. Write a hook_post_update_NAME to load that node and return its URL (see sample code below)
  3. Notice that the URL is the internal path, not the alias.

Sample post-update hook from myexample.post_update.php:

/**
 * Print a node's path alias in hook_post_update_NAME().
 */
function myexample_post_update_9000(&$sandbox) {
  $nid = '1';
  $entity = \Drupal\node\Entity\Node::load($nid);

  $url = $entity->toUrl('canonical')->toString(TRUE)->getGeneratedUrl();
  return sprintf("URL in %s: %s", __FUNCTION__, $url);
}

The output is:

[notice] URL in myexample_post_update_9000: /node/1
[notice] Update completed: myexample_post_update_9000

Proposed resolution

Either:

  • Update the docs for hook_post_update_NAME to state that URL aliases are not available.
  • Or: Change the update process to make URL the path alias processor available during hook_post_update_NAME.

Remaining tasks

API changes

Release notes snippet

🐛 Bug report
Status

Active

Version

10.1

Component
Database update 

Last updated 10 days ago

No maintainer
Created by

🇺🇸United States krisahil

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

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇨🇷Costa Rica robert-arias

    I think it’s a mix of both: it was a documentation error during D8, but now it’s an unintended consequence of #3006086: update.php should not process path aliases .

    Proposal:

    Remove the UpdateServiceProvider alter function that it’s removing the tags from the service in charge of retrieving the path alias. Let me explain why:

    It did make sense to remove the service during D8 because, at that time, sites might have not run the updates that were in charge of migrating the path aliases into full featured entities. However, in D10, it doesn’t make sense to keep the UpdateServiceProvider alter (and honestly, not even in D9, but I think it’s wise to keep the removal in D10), because sites upgrading to D10 should already have the path alias entity schema and related config.
    The recommended flow for upgrading to D10 is going from version to version (i.e. if my site it’s on D8, I should update it to D9, and finally to D10). When upgrading, if the site it’s on D8, we have to run the latest D8 updates to then move to D9, so, when running those updates, the updates in charge of creating the path alias entity should have run - making the alter function meaningless in other D8> versions.

    So, why are path aliases not available during updates?

    This is just to give more context into the issue - you can skip it.

    When running updates (either through update.php or Drush), the UpdateKernel is used, instead of DrupalKernel (UpdateKernel extends from DrupalKernel, but overrides some functions to add update-specific logic and minimal handling of the request). One of the functions it overrides it’s discoverServiceProviders(), which, as the name implies, it discovers custom service providers (that allows to register or alter the DI container, depending on the interface implemented). However, the UpdateServiceProvider is undiscoverable (according to how the discovery happens, which it’s another topic), so, what the UpdateKernel does is add it itself.
    When handling the custom service providers, the first action that will run is the register, then, upon container compilation, the compiler passes are going to be triggered, and among then, the compiler pass in charge of running the alter function of the discovered service providers (the compiler pass in charge is ModifyServiceDefinitionsPass).
    It’s right at this point where the service tags are removed from the path_alias.path_processor service, making it “undiscoverable” when the path_processor_manager service collector is run to retrieve tagged services (in this case, services tagged with path_processor_inbound and path_processor_outbound tags) during the execution of the TaggedHandlersPass compiler pass.

    When updates are run, they’re run through the Batch API - they’re gonna be run in order: first updates, then post updates. Each function will trigger a request into the UpdateKernel, making the path alias service unavailable. The reason the post update documentation says:

    [...] At this stage Drupal is already fully repaired so you can use any API as you wish

    is because, when running the UpdateKernel, if there are unresolved dependencies, they’ll be removed when running updates, because, after running the updates, theoretically, they should be resolved (see UpdateCompilerPass if you wanna know more), and the container is rebuilt (after running updater hooks, a cache flush is run). At this point, post updates hooks can make use of any API; however, that’s not gonna be the case for the path alias service, because it’ll always be removed whenever the UpdateKernel is being used (the same happens in Drush, though it handles it a bit differently, but it maintains the same principle).

    Beware

    Although this patch makes the path_alias.path_processor available, there's still an issue related to it when making use of it in certain routes. See: #2548095: Add option to Url() to force the site base_url to be used

Production build 0.71.5 2024