Unverified Commit 5771e076 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3518224 by alecsmrekar, plach: Duplicate path alias when adding node translation

parent c6d8e3fc
Loading
Loading
Loading
Loading
Loading
+22 −6
Original line number Diff line number Diff line
@@ -82,12 +82,28 @@ public function postSave($update) {

    // If we have an alias, we need to create or update a path alias entity.
    if ($alias) {
      if (!$update || !$pid) {
        $path_alias = $path_alias_storage->create([
      $properties = [
        'path' => '/' . $entity->toUrl()->getInternalPath(),
        'alias' => $alias,
        'langcode' => $alias_langcode,
        ]);
      ];

      if (!$pid) {
        // Try to load it from storage before creating it. In some cases the
        // path alias could be created before this function runs. For example,
        // \Drupal\workspaces\EntityOperations::entityTranslationInsert will
        // create a translation, and an associated path alias will be created
        // with it.
        $query = $path_alias_storage->getQuery()->accessCheck(FALSE);
        foreach ($properties as $field => $value) {
          $query->condition($field, $value);
        }
        $ids = $query->execute();
        $pid = $ids ? reset($ids) : $pid;
      }

      if (!$pid) {
        $path_alias = $path_alias_storage->create($properties);
        $path_alias->save();
        $this->set('pid', $path_alias->id());
      }
+5 −0
Original line number Diff line number Diff line
name: 'Path test miscellaneous utilities'
type: module
description: 'Utilities for path testing'
package: Testing
version: VERSION
+40 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\path_test_misc\Hook;

use Drupal\Core\Hook\Attribute\Hook;
use Drupal\node\NodeInterface;

/**
 * Hook implementations for path_test_misc.
 */
class PathTestMiscHooks {

  /**
   * Implements hook_ENTITY_TYPE_presave() for node entities.
   *
   * This is invoked from testAliasDuplicationPrevention.
   */
  #[Hook('node_presave')]
  public function nodePresave(NodeInterface $node): void {
    if ($node->getTitle() !== 'path duplication test') {
      return;
    }

    // Update the title to be able to check that this code ran.
    $node->setTitle('path duplication test ran');

    // Create a path alias that has the same values as the one in
    // PathItem::postSave.
    $path = \Drupal::entityTypeManager()->getStorage('path_alias')
      ->create([
        'path' => '/node/1',
        'alias' => '/my-alias',
        'langcode' => 'en',
      ]);
    $path->save();
  }

}
+27 −1
Original line number Diff line number Diff line
@@ -4,6 +4,9 @@

namespace Drupal\Tests\path\Functional;

use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;

/**
 * Tests the Path Node form UI.
 *
@@ -14,7 +17,7 @@ class PathNodeFormTest extends PathTestBase {
  /**
   * {@inheritdoc}
   */
  protected static $modules = ['node', 'path'];
  protected static $modules = ['node', 'path', 'path_test_misc'];

  /**
   * {@inheritdoc}
@@ -59,4 +62,27 @@ public function testNodeForm(): void {
    $assert_session->fieldNotExists('path[0][alias]');
  }

  /**
   * Tests that duplicate path aliases don't get created.
   */
  public function testAliasDuplicationPrevention(): void {
    $this->drupalGet('node/add/page');
    $edit['title[0][value]'] = 'path duplication test';
    $edit['path[0][alias]'] = '/my-alias';
    $this->submitForm($edit, 'Save');

    // Test that PathItem::postSave detects if a path alias exists
    // before creating one.
    $aliases = \Drupal::entityTypeManager()
      ->getStorage('path_alias')
      ->loadMultiple();
    static::assertCount(1, $aliases);
    $node = Node::load(1);
    static::assertInstanceOf(NodeInterface::class, $node);

    // This updated title gets set in PathTestMiscHooks::nodePresave. This
    // is a way of ensuring that bit of test code runs.
    static::assertEquals('path duplication test ran', $node->getTitle());
  }

}