したがって、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。実際のよく説明された答えをここで探します。本当に理解したいです。誰かが本当の精巧な答えを書くのに時間をかけてくれれば幸いです。
MVC Router
クラス(より広範なフロントコントローラーの一部)は、HTTPリクエストのURL(具体的には、パスコンポーネント(および場合によってはクエリ文字列))を分類します。
Router
は、パスコンポーネントの最初の1つまたは2つの部分を対応するルートの組み合わせ(Controller
/Action [method]、または単にデフォルトアクションを実行するController
(メソッド)。
アクションまたはコマンドは、特定のController
からのmethodオフです。
通常、_abstract Controller
_とController
の多くの子があり、Webページごとに1つ(一般的に言えば)あります。
URLに存在する場合、Router
も必要なController
のメソッドに引数を渡すと言う人もいます。
注:オブジェクト指向プログラミングの純粋主義者は、単一責任の原則に従って、URLのルーティングコンポーネントと- dispatchingController
クラスは2つの別々の責任です。その場合、Dispatcher
classは実際に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
を使用するように指示できます。sync
はContactConroller::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とstring
valueの間に正規表現の一致があるかどうかを確認します第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
_
私のフレームワークからのルータークラス。コードは物語を語ります:
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;
}