21

そのため、MVC (フレームワーク MVC ではなく、実際の MVC) をもう少し詳しく研究し始め、小さなフレームワークを開発しようとしています。私は、Symphony や Zend などの他のフレームワークを読み、それらがどのように機能するかを確認し、それを自分で実装しようとしています。

私が行き詰まった場所は、URL ルーティング システムでした。

<?php
namespace Application\Common;

class RouteBuilder {

    public function create($name, $parameters) {
        $route           = new Route($name);
        $route->resource = array_keys($parameters)[0];
        $route->defaults = $parameters["defaults"];
        $notation        = $parameters["notation"];
        $notation = preg_replace("/\[(.*)\]/", "(:?$1)?", $notation);
        foreach ($parameters["conditions"] as $param => $condition) {
            $notation = \str_replace($param, $condition, $notation);
        }

        $notation = preg_replace("/:([a-z]+)/i", "(?P<$1>[^/.,;?\n]+)", $notation);

        //@TODO: Continue pattern replacement!!
    }
}
/* How a single entry looks like
 * "main": {
    "notation": "/:action",
    "defaults": {
        "resource"  :   "Authentication",
    },
    "conditions":   {
        ":action"   :   "(login)|(register)"
    }
},

 */

頭をきちんと包み込むことができません。ここからの申請の流れは?

パターンが生成されます。おそらく、Routeオブジェクトの下に保持されるRequestオブジェクトか何かです。それはどのように機能しますか?

PSここで、よく説明された本当の答えを探しています。私は本当に主題を理解したいです。誰かが本当に精巧な答えを書くために時間を割いてくれたら幸いです。

4

2 に答える 2

31

MVCRouterクラス (より広範なFront Controllerの一部) は、HTTP 要求の URL、特にパス コンポーネント (および場合によってはクエリ文字列) を分解します。

Router、パス コンポーネントの最初の 1 つまたは 2 つの部分を、対応するルートの組み合わせ ( Controller/ アクション [メソッド]、またはControllerデフォルト アクションを実行するもの (メソッド) のみ) と一致させようとします。

アクションまたはコマンドは、特定Controller.

通常、Web ページごとに 1 つ以上abstract Controllerの の子が存在します (一般的に言えば)。Controller

URL に引数が存在する場合、Routerは目的の のメソッドにも引数を渡すと言う人もいるかもしれません。Controller

: オブジェクト指向プログラミングの純粋主義者は、単一責任の原則に従い、URL のコンポーネントのルーティングとクラスのディスパッチは2 つの別個の責任であると主張するかもしれません。Controllerその場合、Dispatcherクラスは実際に をインスタンス化し、Controllerそのメソッドの 1 つにクライアント HTTP 要求から派生した引数を渡します。

例 1:Controllerが、アクションも引数もありません。

http://localhost/contactGET 要求では、フォームが表示される場合があります。

コントローラー= 契約

アクション= デフォルト (通常はindex()メソッド)

======================

例 2:Controllerアクションはありますが、引数はありません。

http://localhost/contact/sendPOST 要求では、これによりサーバー側の検証が開始され、メッセージの送信が試行される場合があります。

コントローラー= 契約

アクション= 送信

======================

例 3: Controller、アクション、および引数。

http://localhost/contact/send/syncPOST 要求では、これによりサーバー側の検証が開始され、メッセージの送信が試行される場合があります。ただし、この場合、JavaScript がアクティブになっていない可能性があります。したがって、グレースフル デグラデーションをサポートするには、画面の再描画をサポートし、 の代わりに ,の HTTP ヘッダーで応答するContactControllerを使用するように に指示できます。に引数として渡されます。私の例は完全に恣意的で作り話でしたが、私はそれが法案に合っていると思いました!ViewContent-Type: text/htmlContent-Type: application/jsonsyncContactConroller::send()sync

コントローラー= 契約

アクション= 送信

Arguments = [sync] // はい、配列で引数を渡します!

クラスは、要求されたRouter具体的な子をインスタンス化し、要求されたメソッドをコントローラー インスタンスからController呼び出し、コントローラー メソッドにその引数(存在する場合) を渡します。

1)クラスRouterはまず、インスタンス化できる具象があるかどうかを確認する必要がありControllerます (URL にある名前と「Controller」という単語を使用)。コントローラーが見つかった場合は、要求されたメソッド(アクション) の存在をテストします。

2)具体的な子をインスタンス化するためRouterに実行時に必要な PHP を見つけてロードできない場合(オートローダーを使用することをお勧めします)、配列 (通常Controllerは別のクラス名で見つかりますRoute) をチェックして、要求された URL が一致するかどうかを確認する必要があります。式、それに含まれる要素のいずれか。Routeクラスの基本的なスケルトンは次のとおりです。

注: .*?= 0 個以上の任意の文字、非キャプチャ。

class Route
{
    private $routes = [
        ['url' => 'nieuws/economie/.*?', // regular expression.
         'controller' => 'news',
         'action' => 'economie'],
        ['url' => 'weerbericht/locatie/.*?', // regular expression.
         'controller' => 'weather',
         'action' => 'location']
    ];

    public function __contstruct()
    {

    }

    public function getRoutes()
    {
        return $this->routes;
    }
}

正規表現を使用する理由 URL の 2 番目のスラッシュの後のデータについては、信頼できる照合が行われる可能性は低くなります。

/controller/method/param1/param2/...ここで、param[x] は何でもかまいません!

警告:ターゲティング データにパターン区切り文字 (この場合はスラッシュ「/」) が含まれている場合は、デフォルトの正規表現パターン区切り文字 (「/」) を変更することをお勧めします。ほとんどの無効な URL 文字は適切な選択です。

クラスのメソッドは配列をRouter繰り返し処理して、ターゲット URL と第 2 レベルのインデックスに関連付けられたRoute::routesの間に正規表現の一致があるかどうかを確認します。一致するものが見つかった場合、インスタンス化する具象と、その後に呼び出すメソッドを then が認識します。引数は、必要に応じてメソッドに渡されます。string urlRouterController

以下を表す URL など、エッジ ケースには常に注意してください。

`/`   // Should take you to the home page / HomeController by default
`''`  // Should take you to the home page / HomeController by default
`/gibberish&^&*^&*%#&(*$%&*#`   // Reject
于 2012-09-14T19:32:25.380 に答える
2

私のフレームワークからのルータークラス。コードは次のことを物語っています。

class Router
{
  const default_action = 'index';
  const default_controller = 'index';

  protected $request = array();

  public function __construct( $url )
  {
    $this->SetRoute( $url ? $url : self::default_controller );
  }

  /*
  *  The magic gets transforms $router->action into $router->GetAction();
  */
  public function __get( $name )
  {
    if( method_exists( $this, 'Get' . $name ))
      return $this->{'Get' . $name}();
    else
      return null;
  }

  public function SetRoute( $route )
  {
    $route = rtrim( $route, '/' );
    $this->request = explode( '/', $route );
  }

  private function GetAction()
  {
    if( isset( $this->request[1] ))
      return $this->request[1];
    else
      return self::default_action;
  }

  private function GetParams()
  {
    if( count( $this->request ) > 2 )
      return array_slice ( $this->request, 2 );
    else
      return array();
  }

  private function GetPost()
  {
    return $_SERVER['REQUEST_METHOD'] == 'POST';
  }

  private function GetController()
  {
    if( isset( $this->request[0] ))
      return $this->request[0];
    else
      return self::default_controller;
  }

  private function GetRequest()
  {
    return $this->request;
  }
于 2012-09-14T19:51:25.857 に答える