web-dev-qa-db-ja.com

/ foo / Xから/ bar / Xにユーザーを動的にリダイレクトする方法は?

これまでのところ、私は次のことをしました:

  1. RedirectおよびTokenモジュールをインストールしました。
  2. 私は ワイルドカードをサポートするRedirectモジュールのパッチ を適用しました。
  3. 私は hook_redirect_response_alter を実装するためにRedirectモジュールのパッチを適用しました。
  4. 次のhook_redirect_response_alterトークンのサポートと解析 に定義しました。

    use Drupal\redirect\Entity\Redirect;
    use Symfony\Component\HttpFoundation\RedirectResponse;
    use Drupal\Component\Utility\UrlHelper;
    
    /**
     * Implements hook_redirect_response_alter().
     */
    function MYMODULE_redirect_response_alter(RedirectResponse $response, Redirect $redirect) {
      $uri = $redirect->getRedirect()['uri']; // "internal:/bar/[current-page:url:args:last]"
      if (!empty($uri) && strpos($uri, '[') !== FALSE) {
        $uri = \Drupal::token()->replace($uri); // "internal:/bar/"
        $external = UrlHelper::isValid($uri, TRUE); // bool
        $redirect->setRedirect($external ? $uri : explode('/', $uri, 2)[1]);
        $response->setTargetUrl($redirect->getRedirectUrl()->setAbsolute()->toString()); // "http://localhost/bar/"
      }
    }
    
  5. /admin/config/search/redirectに次のリダイレクトを追加しました:

    • 差出人:foo/*
    • 宛先:/bar/[current-page:url:args:last]

上記に基づいて、foo/Xを入力するとbar/Xにリダイレクトされ、それに応じてfoo/Ybar/Yにリダイレクトすることを期待しています。ただし、上記のトークンは空の文字列に置き換えられます。 [current-page:url:args:value:2]などのトークンを使用する場合も同様ですが、トークンはまったく置き換えられません。トークンもエンティティタイプに基づいて生成されるので、[redirect:url:args:last]を使用しても機能しないことを here も学んだので、Redirectモジュールはそれを認識していません。

パスから2番目の引数を抽出できる可能性がある/admin/help/tokenで見つかったいくつかのトークンを試してみましたが、このタスクに適した、または期待どおりに機能していないことがわかりました。

例えば:

Redirect tokens in Drupal 8 at /admin/help/tokenCurrent page tokens in Drupal 8 at /admin/help/token


もっと詳しく

コメントで提案されているように、トークンのreplace()メソッドに$redirectコンテキストを適用すると、期待どおりに機能しませんでした。

したがって、次の行:

$uri = \Drupal::token()->replace($uri, ['redirect' => $redirect]);

トークンにredirect接頭辞を入力しますが、現在のパスを誤って置き換えます。 [redirect:url:args:join:/]は、すべてのページでadmin/config/search/redirect/edit/25になります。

current-pageトークンのコンテキストを設定しようとしましたが、現在のパスが存在する必要がありますが、リダイレクト中に現在のパスがメニュールーティングテーブルに存在しないため、ロードできません( Url::createFromRequest()\Drupal::request()を試しました。


質問

何が欠けていますか?同じことを達成する簡単な方法はありますか?

3
kenorb

トークンのreplaceメソッドのコンテキストを渡すことが期待どおりに機能しなかったため、カスタムモジュールに新しいトークンを定義して、Drupalパスの特定のコンポーネントを返します(次の ガイド )。

my_redirect.tokens.inc

<?php

/**
 * @file
 * An include file defining custom tokens.
 */

use Drupal\Core\Render\BubbleableMetadata;

/**
 * Implements hook_token_info().
 */
function my_redirect_token_info() {
  $type = [
    'name' => t('Custom URL token for redirect'),
    'description' => t('Tokens helpful for redirect pages.'),
  ];

  $node['url-arg'] = [
    'name' => t("URL Argument"),
    'dynamic' => TRUE,
    'description' => t('Returns a component of the current Drupal path.'),
  ];

  return [
    'types' => ['my_redirect' => $type],
    'tokens' => ['my_redirect' => $node],
  ];
}

/**
 * Implements hook_tokens().
 */
function my_redirect_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {

  $replacements = [];

  if ($type == 'my_redirect') {
    if ($argTokens = \Drupal::token()->findWithPrefix($tokens, 'url-arg')) {
      foreach ($argTokens as $arg => $original) {
        $current_path = \Drupal::service('path.current')->getPath();
        if ($arg === "first") {
          $value = explode('/', $current_path)[1];
        }
        elseif ($arg === "last") {
          $value = end(explode('/', $current_path));
        }
        else {
          $value = explode('/', $current_path)[$arg ?: 0];
        }
        $replacements[$original] = $value;
      }
    }
  }

  return $replacements;
}

したがって、すでに述べたパッチと上記のコードを適用した後、次のリダイレクトルールを使用できます。

  • から:foo/*
  • 宛先:/bar/[my_redirect:url-arg:2]
2
kenorb