Follow-up to #3424962: Allow redirects to be 'disabled'.

Problem/Motivation

When a path alias changes, redirect_path_alias_update() uses findMatchingRedirect() to check for an existing redirect from the old alias. Since #3424962: Allow redirects to be 'disabled' that lookup skips disabled redirects, but the unique key on redirect.hash doesn't. If a disabled redirect holds the old alias, a second one is created and the entity save fails:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '...' for key 'redirect.hash'

With Workspaces support (#3313540: Convert the Redirect entity type to revisionable) this is common: a redirect created in a workspace is disabled in Live but holds its hash, so changing the same alias in Live or in another workspace fails.

Steps to reproduce

  1. Create a node with the alias /x.
  2. Add a disabled redirect from x to any path.
  3. Change the node's alias to /y.

Proposed resolution

Leave a disabled redirect from the old alias alone, as the hook already does for an enabled one:

  • Add RedirectRepository::findBySourceHash(), which finds redirects holding a source's hash, enabled or not.
  • Only create the redirect when neither findMatchingRedirect() nor findBySourceHash() finds one.
  • Use findBySourceHash() in UniqueHashValidator too, so the form and the hook run the same check.

API changes

New RedirectRepository::findBySourceHash(). UniqueHashValidator takes the redirect repository instead of the entity type manager.

Issue fork redirect-3629356

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

amateescu created an issue. See original summary.

amateescu’s picture

Status: Active » Needs review
plach’s picture

Issue summary: View changes
amateescu’s picture

Pushed a follow-up commit: findBySourceHash() now reads the base table directly, since that's where the unique key on hash is. On 8.x-1.x this gives the same result as the entity query. It matters once redirects are revisionable (#3313540: Convert the Redirect entity type to revisionable): inside a workspace an entity query matches the workspace revisions, so a redirect whose source was changed in the workspace wasn't found, and a new redirect from its old source failed on the unique key. Thanks to @plach for spotting this.

A redirect trashed in a workspace has the same problem, because Trash hides it from the check. That part is fixed in Trash: #3630354: A new redirect fails to save when a redirect trashed in the same workspace has the same source.

plach’s picture

Status: Needs review » Reviewed & tested by the community

Looks good and works well, thanks!