CleverStyle Frameworkでのルーティング

CleverStyle Frameworkの多くの側面には、他のほとんどのフレームワークと同じものの代替実装があります。

この記事では、ルーティングデバイス、使用例、このメカニズムに介入する方法、または必要に応じて完全に独自のメカニズムに置き換える方法の例を十分に詳しく説明します。

主な違い


Symfony、Laravel、Yiiなどの一般的なフレームワークでのルーティングと実装の主な違いは、命令性ではなく宣言性です。

つまり、特定の形式でルートを指定し、特定のクラス、メソッド、またはクロージャーをルートにマッピングする代わりに、ルートの構造を記述するだけで、この構造はルートに応じて実行されるコードを理解するのに十分です。

このような構成ではなく規則のアプローチは、コードを記述するときに労力が少なく、特定のページを開くときに呼び出されるコードを理解するために構成を表示する必要がないという意味で便利です。これは、フレームワークで採用された合意から明らかです。

ルーティングの基本


フレームワークビューのURLは、いくつかの部分に分かれています。 最初に、処理の前に、リクエストパラメータ( ?およびそれ以降のすべて)がページパスから削除されます。

次に、次の形式のパスの一般的な形式を取得します(複数のオプションの選択を分離するために使用される| []オプションの独立したパスコンポーネントはグループ化されます)。 :

 [language/] [admin/|api/|cli/] [Module_name [/path [/sub_path [/id1 [/another_subpath [/id2] ] ] ] ] ] 

ネストレベルの数に制限はありません。

最初のステップは、言語接頭辞を確認することです。 ルーティングには参加しません(存在しない場合もあります)が、存在する場合は、ページで使用される言語に影響します。 形式は、使用される言語とその数に依存します。単純な場合( enru )、または地域( en_gbru_ua )を考慮に入れることができます。

言語は、ページのタイプを決定するオプションの部分です。 これは、管理ページ( $Request->admin_path === true )、APIへのリクエスト( $Request->api_path === true )、CLIインターフェースへのリクエスト( $Request->cli_path === true )または通常のユーザーです。明示的に記載されていない場合はページ。

次に、ページを処理するモジュールが決定されます。 このモジュールは、その後$Request->current_moduleとして利用可能です。

モジュールの名前はローカライズできることに注意してください。たとえば、 My_blogモジュールの翻訳に"My_blog" : " "ペアがある場合、モジュールの名前として_を使用できますが、それでも$Request->current_module === 'My_blog'

モジュールが$Request->route分類された後の残りの配列要素は、たとえばカスタムルーティングのためにモジュールで使用できます。

次の手順に進む前に、さらに2つの配列がいっぱいになります。

$Request->route_idsは、整数である$Request->route要素が含まれます(これらは識別子であると想定されます)。 $Request->route_pathは、整数を除く$Request->routeすべての要素が含まれ、モジュール内のルートとして使用されます

早い段階でルーティングを開始する方法


開発者は一連のイベントを自由に使用して、これらの段階で既にくさび止め、自分の裁量で動作を変更できます。

System/Request/routing_replace/beforeイベントは、ページ言語を決定する直前にトリガーされ、元のパスを何らかの方法で文字列として変更することができます。この場所で最低レベルの操作を実行できます。

System/Request/routing_replace/afterイベントは、 $Request->route_idsおよび$Request->route_pathの形成後にトリガーされ、システムによって決定された後に重要なパラメーターを調整できます。

標準の整数識別子の代替としてUUIDサポートを追加する例:

 Event::instance()->on( 'System/Request/routing_replace/after', function ($data) { $route_path = []; $route_ids = []; foreach ($data['route'] as $item) { if (preg_match('/([af\d]{8}(?:-[af\d]{4}){3}-[af\d]{12}?)/i', $item)) { $route_ids[] = $item; } else { $route_path[] = $item; } } if ($route_ids) { $data['route_path'] = $route_path; $data['route_ids'] = $route_ids; } } ); 

ルート構造


ルート構造は、各子レベルのキーが親の拡張であるツリー状のJSONです。隣接するノードの構造がより深い場合、いくつかの最終ノードが空になる場合があります。

現在のシステムモジュールAPI構造の例:

 { "admin" : { "about_server" : [], "blocks" : [], "databases" : [], "groups" : [ "_", "permissions" ], "languages" : [], "mail" : [], "modules" : [], "optimization" : [], "permissions" : [ "_", "for_item" ], "security" : [], "site_info" : [], "storages" : [], "system" : [], "themes" : [], "upload" : [], "users" : [ "_", "general", "groups", "permissions" ] }, "blank" : [], "languages" : [], "profile" : [], "profiles" : [], "timezones" : [] } 

この構造に一致する(実際の)クエリの例:

 GET api/System/blank GET api/System/admin/about_server SEARCH_OPTIONS api/System/admin/users SEARCH api/System/admin/users PATCH api/System/admin/users/42 GET api/System/admin/users/42/groups PUT api/System/admin/users/42/permissions 

最終ルートを取得する


ページパスからルートを取得することは、2つのステップのうち最初のステップにすぎません。 2番目の段階では、現在のモジュールの構成を考慮し、それに応じて最終的なルートを調整します。

これは何のためですか? ユーザーが/Blogsページを開き、ルート構造が次のように構成されているとします( modules/Blogs/index.json ):

 [ "latest_posts", "section", "post", "tag", "new_post", "edit_post", "drafts", "atom.xml" ] 

この場合、 $Request->route_path === []ですが、 $App->controller_path === ['index', 'latest_posts']

indexはモジュールや設定に関係なくここにありますが、 latest_postsすでに設定に依存しています。 実際、ページがAPIまたはCLIリクエストではない場合、不完全なルートを指定すると、フレームワークは各レベルの構成から最初のキーを選択し、構造の奥深くまで到達します。 つまり、 Blogs Blogs/latest_posts似ています。

この意味でのAPIおよびCLIリクエストには違いがあります-この方法でルートの一部を省略することは禁止されており、 _適切なレベルで構造の最初の要素として使用される場合にのみ許可されます。

たとえば、APIの場合、次の構造( modules/Module_name/api/index.json )を持つことができます:

 { "_" : [] "comments" : [] } 

この場合、 api/Module_name api/Module_name/_似ています。 これにより、美しいメソッドでAPIを実行できます(識別子が別の配列にあることに注意してください)。

 GET api/Module_name GET api/Module_name/42 POST api/Module_name PUT api/Module_name/42 DELETE api/Module_name/42 GET api/Module_name/42/comments GET api/Module_name/42/comments/13 POST api/Module_name/42/comments PUT api/Module_name/42/comments/13 DELETE api/Module_name/42/comments/13 

ルート構造ファイルの場所


CleverStyle Frameworkのモジュールは、モジュールフォルダー内にすべてを保存します(フレームワークでは、すべてのビューが1つのフォルダーにあり、すべてのコントローラーが別のフォルダーにあり、すべてのモデルが3番目にあり、すべてのルートが1つのファイルにあります)。

要求のタイプに応じて、JSON形式の異なる構成が使用されます。


同じフォルダーにルートハンドラーがあります。

ルーティングタイプ


CleverStyle Frameworkには2つのタイプのルーティングがあります。ファイルベース(以前に広く使用されていました)とコントローラーベース(現在より多く使用されています)です。

Blogs/latest_postsと、上記の例の最終ルート['index', 'latest_posts']['index', 'latest_posts']ます。

ファイルベースのルーティングの場合、次のファイルが指定された順序で接続されます。

 modules/Blogs/index.php modules/Blogs/latest_posts.php 

コントローラーベースのルーティングを使用する場合、 cs\modules\Blogs\Controllerクラスが存在する必要があります( modules/Blogs/Controller.phpファイル)。次のpublic staticメソッドがあります。

 cs\modules\Blogs\Controller::index($Request, $Response) : mixed cs\modules\Blogs\Controller::latest_posts($Request, $Response) : mixed 

最後以外のファイル/メソッドは省略できることが重要です。これによりエラーが発生することはありません。

次に、より複雑な例、 GET api/Module_name/items/42/comments request GET api/Module_name/items/42/comments見てみましょう。

最初に、API要求とCLI要求では、パスに加えて、HTTPメソッドも重要です。
第二に、 apiサブフォルダがここで使用されます。

ファイルベースのルーティングの場合、次のファイルが指定された順序で接続されます。

 modules/Module_name/api/index.php modules/Module_name/api/index.get.php modules/Module_name/api/items.php modules/Module_name/api/items.get.php modules/Module_name/api/items/comments.php modules/Module_name/api/items/comments.get.php 

コントローラベースのルーティングを使用する場合、 cs\modules\Blogs\api\Controllerクラスが存在する必要があります( modules/Blogs/api/Controller.phpファイル)。次のpublic staticメソッドがあります。

 cs\modules\Blogs\api\Controller::index($Request, $Response) : mixed cs\modules\Blogs\api\Controller::index_get($Request, $Response) : mixed cs\modules\Blogs\api\Controller::items($Request, $Response) : mixed cs\modules\Blogs\api\Controller::items_get($Request, $Response) : mixed cs\modules\Blogs\api\Controller::items_comments($Request, $Response) : mixed cs\modules\Blogs\api\Controller::items_comments_get($Request, $Response) : mixed 

この場合、最後の2つのファイル/コントローラーの少なくとも1つが存在する必要があります。

ご覧のとおり、APIおよびCLIリクエストは、異なるHTTPメソッドでリクエスト処理コードを明示的に分離していますが、これは通常のページと管理ページでは考慮されていません。

コントローラーの引数と戻り値


$Request$Responseは、 cs\Requestcs\Responseインスタンスにすぎません。

単純な場合、戻り値はコンテンツを設定するのに十分です。 APIリクエストの内部では、戻り値はcs\Page::json()に渡され、その他のリクエストではcs\Page::content()渡されます。

 public static function items_comments_get () { return []; } //   public static function items_comments_get () { Page::instance->json([]); } 

無効なHTTPメソッドハンドラー


ユーザーが要求するメソッドのHTTPハンドラーがない場合があります。この場合、イベントの開発にはいくつかのシナリオがあります。

API: cs\modules\Blogs\api\Controller::items_comments()またはcs\modules\Blogs\api\Controller::items_comments_get() (または同様のファイル)がない場合:


CLI:APIに似ていますが、 CLIOPTIONSではなく特別なメソッドであり、 Allowヘッダーではなく、使用可能なメソッドがコンソールに表示されます(呼び出されたメソッドがCLIと異なる場合、終了ステータスは245501 % 256 )に変更されます)。

独自のルーティングシステムを使用する


何らかの理由でフレームワークのルーティングデバイスが気に入らない場合は、個々のモジュールごとにindex.phpファイルのみを作成し、ルーターをそれに接続します。

index.phpindex.jsonコントローラーと構造を必要としないため、ルーティングシステムのほとんどをindex.jsonます。

アクセス権


ルートの各レベルについて、アクセス権がチェックされます。 フレームワークのアクセス権には、グループとラベルの2つの重要なパラメーターがあります。

グループとして、ページへのアクセス権をチェックするとき、管理およびAPIページのオプションのプレフィックスとともにモジュール名が使用され、ルートパス( indexプレフィックスを除く)がラベルとして使用されます。

たとえば、 api/Module_name/items/commentsページの場合、権限のユーザー権限が( group labelスペースを介して)チェックされます。

 api/Module_name index api/Module_name items api/Module_name items/comments 

ユーザーに何らかのレベルでアクセス権がない場合、処理は403 Forbiddenエラーで終了しますが、アクセス権はハンドラーが開始する前の最終ルート形成の段階で決定されるため、前のレベルのハンドラーは実行されません。

最後に


CleverStyle Frameworkでのクエリ処理の実装は、宣言的でありながら非常に強力で柔軟です。

この記事では、ルーティングシステムと開発者にとっての関心の観点から、リクエスト処理の主要な段階について説明していますが、実際には、ニュアンスを掘り下げた場合、まだ学ぶべきことがあります。

このガイドが迷子にならないように十分であることを願っています。 ここで、特定の要求に応じてどのコードが呼び出されたかを判断するために、構成を調べる必要さえないことが明確になるはずです。 ターゲットフォルダーにController.phpが存在することで使用されるルーティングの種類を判断し、対応するファイルを開くだけで十分です。

記事5.29の執筆時点でのフレームワークの現在のバージョンは、新しいバージョンで変更が可能です。リリースノートに従ってください。

GitHubリポジトリ
» フレームワークのドキュメント

建設的なコメントはいつものように歓迎します。

Source: https://habr.com/ru/post/J307690/


All Articles