You are here

public function AliasStorage::save in Multiversion 8

Saves a path alias to the database.

@thrown \InvalidArgumentException Thrown when either the source or alias has not a starting slash.

Parameters

string $source: The internal system path.

string $alias: The URL alias.

string $langcode: (optional) The language code of the alias.

int|null $pid: (optional) Unique path alias identifier.

Return value

array|false FALSE if the path could not be saved or an associative array containing the following keys:

  • source (string): The internal system path with a starting slash.
  • alias (string): The URL alias with a starting slash.
  • pid (int): Unique path alias identifier.
  • langcode (string): The language code of the alias.
  • original: For updates, an array with source, alias and langcode with the previous values.

Overrides AliasStorage::save

File

src/AliasStorage.php, line 56

Class

AliasStorage
Extends the core AliasStore class. We need this to make possible aliases to work with Multiversion and Replication.

Namespace

Drupal\multiversion

Code

public function save($source, $alias, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED, $pid = NULL) {
  if (!$this->connection
    ->schema()
    ->fieldExists('url_alias', 'workspace')) {
    return parent::save($source, $alias, $langcode, $pid);
  }
  if ($source[0] !== '/') {
    throw new \InvalidArgumentException(sprintf('Source path %s has to start with a slash.', $source));
  }
  if ($alias[0] !== '/') {
    throw new \InvalidArgumentException(sprintf('Alias path %s has to start with a slash.', $alias));
  }

  // Skip saving a new alias if migration running.
  if ($this->state
    ->get('skip_alias_save', FALSE)) {
    return FALSE;
  }

  // Set workspace equal with the active workspace just for path aliases for
  // multiversionable entities. For all other aliases set workspace 0, they
  // will be available on all workspaces.
  $workspace = 0;

  // Don't inject this service to avoid circular reference error.
  $path_validator = \Drupal::service('path.validator');
  $url = $path_validator
    ->getUrlIfValidWithoutAccessCheck($source);
  if ($url instanceof Url) {
    $route_name = $url
      ->getRouteName();
    $route_name_parts = explode('.', $route_name);
    if ($route_name_parts[0] === 'entity' && $this
      ->isMultiversionableEntityType($route_name_parts[1])) {
      $workspace = $this->workspaceManager
        ->getActiveWorkspaceId();
    }
  }
  $fields = [
    'source' => $source,
    'alias' => $alias,
    'langcode' => $langcode,
    'workspace' => $workspace,
  ];

  // Insert or update the alias.
  if (empty($pid)) {
    $try_again = FALSE;
    try {
      $query = $this->connection
        ->merge(static::TABLE)
        ->condition('workspace', $fields['workspace'])
        ->condition('source', $fields['source'])
        ->condition('langcode', $fields['langcode'])
        ->fields($fields);
      $result = $query
        ->execute();
    } catch (\Exception $e) {

      // If there was an exception, try to create the table.
      if (!($try_again = $this
        ->ensureTableExists())) {

        // If the exception happened for other reason than the missing table,
        // propagate the exception.
        throw $e;
      }
    }

    // Now that the table has been created, try again if necessary.
    if ($try_again) {
      $query = $this->connection
        ->merge(static::TABLE)
        ->condition('workspace', $fields['workspace'])
        ->condition('source', $fields['source'])
        ->condition('langcode', $fields['langcode'])
        ->fields($fields);
      $result = $query
        ->execute();
    }
    $pid = $this->connection
      ->select(static::TABLE)
      ->fields(static::TABLE, [
      'pid',
    ])
      ->condition('workspace', $fields['workspace'])
      ->condition('source', $fields['source'])
      ->condition('langcode', $fields['langcode'])
      ->condition('alias', $fields['alias'])
      ->execute()
      ->fetchField();
    $fields['pid'] = $pid;
    if ($result == Merge::STATUS_INSERT || $result == Merge::STATUS_UPDATE) {
      $operation = 'insert';
    }
  }
  else {

    // Fetch the current values so that an update hook can identify what
    // exactly changed.
    try {
      $original = $this->connection
        ->query('SELECT source, alias, langcode FROM {url_alias} WHERE pid = :pid', [
        ':pid' => $pid,
      ])
        ->fetchAssoc();
    } catch (\Exception $e) {
      $this
        ->catchException($e);
      $original = FALSE;
    }
    $fields['pid'] = $pid;
    $query = $this->connection
      ->update(static::TABLE)
      ->fields($fields)
      ->condition('pid', $pid);
    $pid = $query
      ->execute();
    $fields['original'] = $original;
    $operation = 'update';
  }
  if ($pid) {

    // @todo Switch to using an event for this instead of a hook.
    $this->moduleHandler
      ->invokeAll('path_' . $operation, [
      $fields,
    ]);
    Cache::invalidateTags([
      'route_match',
    ]);
    return $fields;
  }
  return FALSE;
}