web-dev-qa-db-ja.com

MVCルーティングはどのように機能しますか?

したがって、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オブジェクトの下に保持されるオブジェクト、それから何ですか?それはどのように機能しますか?

P.S。実際のよく説明された答えをここで探します。本当に理解したいです。誰かが本当の精巧な答えを書くのに時間をかけてくれれば幸いです。

21
Madara's Ghost

MVC Routerクラス(より広範なフロントコントローラーの一部)は、HTTPリクエストのURL(具体的には、パスコンポーネント(および場合によってはクエリ文字列))を分類します。

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

アクションまたはコマンドは、特定のControllerからのmethodオフです。

通常、_abstract Controller_とControllerの多くの子があり、Webページごとに1つ(一般的に言えば)あります。

URLに存在する場合、Routerも必要なControllerのメソッドに引数を渡すと言う人もいます。

:オブジェクト指向プログラミングの純粋主義者は、単一責任の原則に従って、URLのルーティングコンポーネントと- dispatchingControllerクラスは2つの別々の責任です。その場合、Dispatcherclassは実際にControllerをインスタンス化し、そのメソッドの1つにクライアントHTTPリクエストから派生した引数を渡します。

例1:Controller、ただしアクションや引数はありません。

_http://localhost/contact_ GETリクエストでは、フォームが表示される場合があります。

コントローラ =契約

Action =デフォルト(一般的にはindex()メソッド)

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

例2:Controllerとアクション、引数なし

_http://localhost/contact/send_ POSTリクエストの場合、これはサーバー側の検証を開始し、メッセージの送信を試みる可能性があります。

コントローラ =契約

アクション =送信

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

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

_http://localhost/contact/send/sync_ POSTリクエストの場合、これはサーバー側の検証をキックしてメッセージの送信を試みる可能性があります。ただし、この場合、JavaScriptがアクティブでない可能性があります。正常な低下の場合、ContactControllerに、画面の再描画をサポートし、_Content-Type: text/html_ではなく、_Content-Type: application/json_のHTTPヘッダーで応答するViewを使用するように指示できます。syncContactConroller::send()への引数として渡されます。注意してください、私のsyncの例は完全に恣意的で構成されていましたが、私はそれで十分だと思いました!

コントローラ =契約

アクション =送信

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

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

1)Routerクラスは、インスタンス化できる具体的なControllerがあるかどうかを最初に確認する必要があります( URLに含まれる名前に加えて、「コントローラー」という単語。コントローラが見つかった場合、 リクエストされたメソッドの存在をテスト (アクション)。

2)Routerが実行時に必要なPHPを見つけてロードできない場合(- autoloader をお勧めします)具象Controllerの子をインスタンス化するには、配列(通常は別のクラス名Routeにあります)をチェックして、要求されたURLかどうかを確認します- matches 、正規表現を使用して、その中に含まれる任意の要素Routeクラスの基本的なスケルトンが続きます。

注:_.*?_ =ゼロ以上の任意の文字、非キャプチャー。

_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]はanything

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

Routerクラスのメソッドは、_Route::routes_配列を反復処理して、ターゲットURLとstringvalueの間に正規表現の一致があるかどうかを確認します第2レベルのurlインデックスに関連付けられています。一致が見つかると、Routerはインスタンス化する具体的なControllerと、呼び出す後続のメソッドを認識します。引数は必要に応じてメソッドに渡されます。

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

_`/`   // Should take you to the home page / HomeController by default
`''`  // Should take you to the home page / HomeController by default
`/gibberish&^&*^&*%#&(*$%&*#`   // Reject
_
29
w00

私のフレームワークからのルータークラス。コードは物語を語ります:

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;
  }
2
JvdBerg