0

解決済み:

@SJFrK のおかげで、私の問題は解決されました。次のクラスを使用すると、必要なことを実行できます。質問はクラスに続きます。

class Redirects
{
    /*
    |--------------------------------------------------------------------------
    | Placeholder Types
    |--------------------------------------------------------------------------
    |
    | An array of placeholder types thatalow specific characters in a source
    | route or URL.
    |
    */

    private static $placeholders = array(
        ':all' => '.*',
        ':alpha' => '[a-z]+',
        ':alphanum' => '[a-z0-9]+',
        ':any' => '[a-z0-9\.\-_%=]+',
        ':num' => '[0-9]+',
        ':segment' => '[a-z0-9\-\_]+',
        ':segments' => '[a-z0-9\-\_\/]+',
    );

    /*
    |--------------------------------------------------------------------------
    | Computed Replacements
    |--------------------------------------------------------------------------
    |
    | An array that contains converted source placeholders.
    |
    */

    private static $computed_replacements = array();

    /*
    |--------------------------------------------------------------------------
    | Computed Replacements
    |--------------------------------------------------------------------------
    |
    | Class-scoped string that contains a replacement route or URL from
    | site.redirects.
    |
    */

    private static $destination;

    /**
     * Check for a redirect. If it exists, then redirect to it's computed replacement.
     *
     * @return Response
     */
    public static function redirect()
    {
        // Only do this if redirects have been defined.
        if (Config::has('site.redirects') && count(Config::get('site.redirects') > 0))
        {
            $route = URI::current();

            // Get the available placeholders from static::$placeholders and
            // convert them into applicable options for the pattern.
            $available_placeholders = '';
            foreach (static::$placeholders as $placeholder => $expression)
                $available_placeholders .= ltrim("$placeholder|", ':');
            $available_placeholders = rtrim($available_placeholders, '|');

            // Define the pattern.
            $pattern = '/\((\w+):('.$available_placeholders.')\)/';

            // Get the redirects.
            $redirects = Config::get('site.redirects');

            // For each redirect, convert all the place holders and resulting
            // values, and check for a match. If one exists, then redirect to it.
            foreach ($redirects as $from => $to) {
                static::$computed_replacements = array();
                static::$destination = $to;
                $from = rtrim($from, '/');
                $to = rtrim($to, '/');

                // Convert the placeholders in $from (if any)
                $converted_placeholders = preg_replace_callback($pattern, function($captures) {
                    static::$computed_replacements[] = $captures[1];
                    return '('.static::$placeholders[":{$captures[2]}"].')';
                }, $from);

                // Get the replacements
                $converted_replacements = preg_replace_callback("#^{$converted_placeholders}$#i", function($captures) {
                    $output = static::$destination;
                    for ($c = 1, $n = count($captures); $c < $n; ++$c)
                    {
                        $value = array_shift(static::$computed_replacements);
                        $output = str_replace("<$value>", $captures[$c], $output);
                    }
                    return $output;
                }, $route);

                // If the current route matches the converted expression, then redirect.
                if (preg_match("!^{$converted_placeholders}$!i", $route))
                    return Redirect::to($converted_replacements, 301)
                        ->with('moved-from', $route)
                        ->with('moved-from-rule', "'$from': '".static::$destination."'");
            }
        }
        else return;
    }
}

前書き

私はLaravel (FTW) で静的な Web サイト バンドルを作成している最中ですが、回避できないような問題に遭遇しました。

アプリには構成ファイル ( config/site.php) が含まれています。このファイルには、とりわけ、リダイレクト ルックアップの配列が含まれています。アイデアは、各検索 URI で一致をチェックしてから、代わりの URI にリダイレクトすることです (もちろん 301 リダイレクトを使用)。これは、静的な HTML サイトをバンドルに移動する場合に役立ちます。

配列の形式は次のとおりです。

'redirects' => array(
    '<source>' => '<destination>'
)

内に<source>、ユーザーは次のものを含めることができます。

  1. 正規表現
  2. Laravel スタイルのプレースホルダー: (:any)(:all)(:num)、または(:alpha)- 最後のものを追加しました。

たとえば、ユーザーは次のリダイレクトを使用することができます (私は、<destination>より美しいので角かっこを使用することを選択したことに注意してください - 正規表現に変換されます [以下のクラスを参照]):

'(:all).html' => '<1>'

これにより、 で終わるすべてのページ.htmlが、それを含まないルートに誘導されます。例:http://example.com/about.htmlにリダイレクトしhttp://example.com/aboutます。

問題

読みやすい (そして快適なコーディング) ために、各パラメーターに「名前を付ける」ことができるようにしたいと考えています。私がやりたいのは、各プレースホルダーに名前を付け<source>(これはもちろんオプションです)、プレースホルダーの種類を定義することです。例えば:

'(name:all).html' => '<name>'

ここで、プレースホルダーに名前を付けることができることを考えると、当然、 内で任意の順序にすることができます<destination>(たとえば、宛先 URI の順序の変更に注意してください)。

'Products/(name:any)-(category:any)-(id:num).html' => 'products/<category>/<id>/<name>/overview'

通常のプレースホルダー構文を使用すると、これを次のように解釈できます。

'Products/(:any)-(:any)-(:num).html' => 'products/<2>/<3>/<1>'

とにかく、これはフォールバックです..を使用して、名前を対応するキャプチャグループに置き換える方法を見つける必要がありますpreg_replace. しかし、名前付きパラメータ/キャプチャを使用することはできないようです:

名前付きパラメータ

で名前付きパラメーターを使用するのが簡単な方法preg_replaceですが、(私が理解しているように) PHP はそれをサポートしていません。

この方法を使用すると、同じ種類の代替ツールを使用してタスクを完了することができるため、使用できないのは少し残念です.

とはいえ、私は喜んでもう少し複雑なものに戻します (これは良いことです)。問題は、私には方法がわかりません-そして解決策が私に来ていないということです. 私はSilex RouteCompilerクラスを見てきましたが、完全には理解していません。Laravel のバックボーンが Symfony コンポーネント セット (Silex によく似ています) に基づいて構築されていることを考えると、必要なことを達成するためのより良い方法があるかもしれません。

誰かが同じ種類の要件を持っていて、おそらく解決策を見つけましたか? ここでの助けは単に素晴らしいでしょう! 前もって感謝します。

現在のクラス

リダイレクトを処理するクラスのソースは次のとおりです。ファイルRedirects::handle()を呼び出すだけです。routes.php

class Redirects
{
    private static $placeholders = array(
        ':any' => '[a-zA-Z0-9\.\-_%=]+',
        ':num' => '[0-9]+',
        ':alpha' => '[a-z]+', //added
        ':all' => '.*',
    );

    private static $replacement_identifiers = array(
        '(\<([0-9]+)\>)' => '$$1',
    );

    /**
     * Create the applicable regex placeholders
     *
     * @param  string  &$from
     * @param  string  &$to
     * @return void
     */
    protected static function placeholders(string &$from, string &$to)
    {
        // Replace the <source> with a match expression
        foreach (static::$placeholders as $placeholder => $expression)
            $from = str_replace("({$placeholder})", "({$expression})", $from);

        // Replace the <destination> with a replacement expression
        foreach (static::$replacement_identifiers as $identifier => $expression)
            if (preg_match($identifier, $to))
                $to = preg_replace($identifier, $expression, $to);
    }

    /**
     * Return the response of any redirects, or void if none
     *
     * @return Response|void
     */
    public static function handle()
    {
        $route = URI::current();
        if (Config::has('site.redirects'))
        {
            $redirects = Config::get('site.redirects');
            foreach ($redirects as $from => $to) {
                $from = rtrim($from, '/');
                static::placeholders($from, $to);
                if (preg_match("!^{$from}$!i", $route))
                {
                    if (strpos($to, '$') !== false and strpos($from, '(') !== false)
                        $to = preg_replace("!^{$from}$!i", $to, $route);
                    return Redirect::to($to, 301)->with('Moved-From', $route);
                }
                else return;
            }
        }
        else return;
    }
}
4

1 に答える 1

1

これはあなたが望むことを行うテストケースです。おそらくこれをあなたのクラスに組み込むことができますか?:

<?php
class Redirects {
private static $placeholders = array(
    ':any' => '[a-zA-Z0-9\.\-_%=]+',
    ':num' => '[0-9]+',
    ':alpha' => '[a-z]+', //added
    ':all' => '.*',
);

private static $tmp;
private static $tmpValue;

public static function handle() {
    $case = array('Products/(name:any)-(category:any)-(id:num).html' => 'products/<category>/<id>/<name>/overview');
    $test = 'Products/productName-categoryName-123.html';       // products/categoryName/123/productName/overview

    $pattern = '/\(\s*?(\w*?)\s*?:\s*?(\w*?)\s*?\)/';

    foreach ($case as $k => $v) {
        self::$tmp = array();
        self::$tmpValue = $v;

        $step1 = preg_replace_callback($pattern, array(self, 'replace_step1'), $k);
        $step2 = preg_replace_callback('#' . $step1 . '#', array(self, 'replace_step2'), $test);

        print 'case: ' . $k . '<br>';
        print 'step1: ' . $step1 . '<br>';
        print 'step2: ' . $step2 . '<br>';
    }
}

private static function replace_step1($matches) {
    self::$tmp[] = $matches[1];

    return '(' . self::$placeholders[':' . $matches[2]] . ')';
}

private static function replace_step2($matches) {
    $str = self::$tmpValue;

    for ($i = 1, $n = count($matches); $i < $n; ++$i) {
        $value = array_shift(self::$tmp);

        $str = str_replace('<' . $value . '>', $matches[$i], $str);
    }

    return $str;
}
}

Redirects::handle();

最初に名前付きプレースホルダーを実際の PREG プレースホルダーに置き換え、それらを配列に格納し$tmpます。$test次に、テスト文字列がそのパターンに一致するかどうかをチェックし、配列$step1に従ってそれらを置き換えます。$tmp

于 2012-10-05T13:05:28.440 に答える