アプリケーションはどのように動作しますか?

あなたは今、Netteドキュメントの基本憲章を読んでいます。Webアプリケーションがどのように機能するかの全体像を学びます。AからZまで、誕生の瞬間からPHPスクリプトの最後の処理まで。読み終えた後、あなたは知っているでしょう:

  • 全体がどのように機能するか
  • Bootstrap、Presenter、DIコンテナとは何か
  • ディレクトリ構造はどのようになっているか

ディレクトリ構造

WebProjectと呼ばれるWebアプリケーションのスケルトンの例を開き、読みながら言及されているファイルを見ることができます。

ディレクトリ構造は次のようになります。

web-project/
├── app/                      ← アプリケーションディレクトリ
│   ├── Core/                 ← 実行に必要な基本クラス
│   │   └── RouterFactory.php ← URLアドレスの設定
│   ├── Presentation/         ← Presenter、テンプレートなど
│   │   ├── @layout.latte     ← レイアウトテンプレート
│   │   └── Home/             ← Home Presenterのディレクトリ
│   │       ├── HomePresenter.php ← Home Presenterクラス
│   │       └── default.latte ← defaultアクションのテンプレート
│   └── Bootstrap.php         ← ブートストラップクラス Bootstrap
├── bin/                      ← コマンドラインから実行されるスクリプト
├── config/                   ← 設定ファイル
│   ├── common.neon
│   └── services.neon
├── log/                      ← ログ記録されたエラー
├── temp/                     ← 一時ファイル、キャッシュなど
├── vendor/                   ← Composerによってインストールされたライブラリ
│   ├── ...
│   └── autoload.php          ← インストールされたすべてのパッケージのオートローディング
├── www/                      ← 公開ディレクトリまたはプロジェクトのドキュメントルート
│   ├── .htaccess             ← mod_rewriteルール
│   └── index.php             ← アプリケーションが起動する最初のファイル
└── .htaccess                 ← www以外のすべてのディレクトリへのアクセスを禁止

ディレクトリ構造は自由に変更でき、フォルダの名前を変更したり移動したりできます。完全に柔軟です。さらに、Netteは賢い自動検出機能を備えており、URLベースを含むアプリケーションの場所を自動的に認識します。

少し大きなアプリケーションでは、Presenterとテンプレートのフォルダをサブディレクトリに分割し、クラスをモジュールと呼ばれる名前空間に分割できます。

www/ ディレクトリは、プロジェクトのいわゆる公開ディレクトリまたはドキュメントルートを表します。アプリケーション側で何も設定を変更することなく名前を変更できます。ただし、ドキュメントルートがこのディレクトリを指すようにホスティングを設定する必要があります。

WebProjectは、Composerを使用してNetteを含めて直接ダウンロードすることもできます。

composer create-project nette/web-project

LinuxまたはmacOSでは、log/ および temp/ ディレクトリに書き込み権限を設定してください。

WebProjectアプリケーションは実行準備ができており、何も設定する必要はなく、www/ フォルダにアクセスしてブラウザですぐに表示できます。

HTTPリクエスト

すべては、ユーザーがブラウザでページを開いたときに始まります。つまり、ブラウザがHTTPリクエストでサーバーにノックするときです。リクエストは、公開ディレクトリ www/ にある単一のPHPファイル、つまり index.php に向けられます。アドレス https://example.com/product/123 へのリクエストであるとしましょう。適切なサーバー設定のおかげで、このURLも index.php ファイルにマッピングされ、実行されます。

そのタスクは次のとおりです。

  1. 環境を初期化する
  2. ファクトリを取得する
  3. リクエストを処理するNetteアプリケーションを起動する

どのファクトリですか?私たちはトラクターではなく、Webページを作成しています!お待ちください、すぐに説明します。

「環境の初期化」という言葉は、例えばTracyを有効にすることを意味します。これは、エラーのログ記録や視覚化のための素晴らしいツールです。本番サーバーではエラーをログに記録し、開発サーバーでは直接表示します。したがって、初期化には、Webが本番モードで実行されているか開発モードで実行されているかを判断することも含まれます。これを行うために、Netteは賢い自動検出を使用します。Webをlocalhostで実行すると、開発モードで実行されます。したがって、何も設定する必要はなく、アプリケーションは開発と本番展開の両方にすぐに準備ができています。Bootstrapクラスに関する章で、これらの手順が実行され、詳細に説明されています。

3番目のポイント(はい、2番目はスキップしましたが、戻ってきます)は、アプリケーションの起動です。Netteでは、HTTPリクエストの処理は Nette\Application\Application クラス(以下 Application)が担当します。したがって、アプリケーションを起動すると言うとき、具体的にはこのクラスのオブジェクトで run() という適切な名前のメソッドを呼び出すことを意味します。

Netteは、実証済みの方法論に従ってクリーンなアプリケーションを作成するように導くメンターです。そして、それらの完全に実証済みの方法論の1つは、dependency injection、略してDIと呼ばれます。現時点ではDIの説明で負担をかけたくありません。それについては別の章があります。重要な結果は、主要なオブジェクトは通常、DIコンテナ(略してDIC)と呼ばれるオブジェクトのファクトリによって作成されることです。はい、それが少し前に話したファクトリです。そして、それは Application オブジェクトも作成します。そのため、最初にコンテナが必要です。Configurator クラスを使用してそれを取得し、Application オブジェクトを作成させ、その上で run() メソッドを呼び出すことで、Netteアプリケーションが起動します。これはまさにindex.phpファイルで行われていることです。

Nette Application

Applicationクラスには1つのタスクしかありません:HTTPリクエストに応答することです。

Netteで書かれたアプリケーションは、多数のいわゆるPresenter(他のフレームワークではコントローラーという用語に出会うかもしれませんが、同じものです)に分割されます。これらは、Webサイトの特定のページ(ホームページ、eコマースの製品、ログインフォーム、サイトマップフィードなど)を表すクラスです。アプリケーションは1つから数千のPresenterを持つことができます。

Applicationは、まずいわゆるルーターに、現在のリクエストを処理するためにどのPresenterに渡すかを決定するように依頼します。ルーターは、誰の責任かを決定します。入力URL https://example.com/product/123 を見て、設定方法に基づいて、これが例えば id: 123 の製品を表示する(showアクションを要求するPresenter Product の仕事であると判断します。Presenter + アクションのペアは、Product:show のようにコロンで区切って記述するのが良い習慣です。

したがって、ルーターはURLを Presenter:action + パラメータのペア、この場合は Product:show + id: 123 に変換しました。そのようなルーターがどのように見えるかは、app/Core/RouterFactory.php ファイルで確認でき、ルーティングの章で詳細に説明されています。

続けましょう。ApplicationはPresenterの名前を知っているので、次に進むことができます。ProductPresenter クラスのオブジェクトを作成します。これはPresenter Product のコードです。より正確には、Presenterを作成するようにDIコンテナに依頼します。なぜなら、作成するのはDIコンテナの仕事だからです。

Presenterは次のようになります。

class ProductPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private ProductRepository $repository,
	) {
	}

	public function renderShow(int $id): void
	{
		// モデルからデータを取得し、テンプレートに渡します
		$this->template->product = $this->repository->getProduct($id);
	}
}

リクエストの処理はPresenterが引き継ぎます。そして、タスクは明確です:id: 123 でアクション show を実行します。Presenterの言葉で言えば、これは renderShow() メソッドが呼び出され、パラメータ $id123 を受け取ることを意味します。

Presenterは複数のアクションを処理できます。つまり、複数の render<Action>() メソッドを持つことができます。ただし、1つまたはできるだけ少ないアクションを持つPresenterを設計することをお勧めします。

したがって、renderShow(123) メソッドが呼び出されました。そのコードは架空の例ですが、$this->template への書き込みによってデータがテンプレートにどのように渡されるかを見ることができます。

その後、Presenterは応答を返します。これは、HTMLページ、画像、XMLドキュメント、ディスクからのファイルの送信、JSON、または別のページへのリダイレクトなどです。重要なのは、明示的に応答方法を指示しない場合(これは ProductPresenter の場合です)、応答はHTMLページを含むテンプレートのレンダリングになることです。なぜですか?なぜなら、99%の場合、テンプレートをレンダリングしたいので、Presenterはこの動作をデフォルトと見なし、作業を楽にしたいからです。それがNetteの目的です。

どのテンプレートをレンダリングするかを指定する必要さえありません。パスは自動的に推測されます。show アクションの場合、単に ProductPresenter クラスと同じディレクトリにある show.latte テンプレートをロードしようとします。また、@layout.latte ファイルでレイアウトを見つけようとします(テンプレートの検索について詳しくはこちら)。

そして、テンプレートがレンダリングされます。これでPresenterとアプリケーション全体のタスクが完了し、作業は完了です。テンプレートが存在しない場合、404エラーページが返されます。Presenterについて詳しくは、Presenterページをご覧ください。

念のため、少し異なるURLでプロセス全体を要約してみましょう。

  1. URLは https://example.com になります
  2. アプリケーションを起動し、コンテナを作成し、Application::run() を実行します
  3. ルーターはURLを Home:default ペアとしてデコードします
  4. HomePresenter クラスのオブジェクトが作成されます
  5. renderDefault() メソッドが呼び出されます(存在する場合)
  6. 例えば @layout.latte のレイアウトを持つ default.latte などのテンプレートがレンダリングされます

おそらく、今、多くの新しい概念に出会ったかもしれませんが、それらが意味をなすことを願っています。Netteでのアプリケーション開発は非常に快適です。

テンプレート

テンプレートについて言えば、NetteではLatteテンプレートシステムが使用されます。そのため、テンプレートの拡張子は .latte です。Latteが使用される理由は、PHPで最も安全なテンプレートシステムであると同時に、最も直感的なシステムでもあるためです。多くの新しいことを学ぶ必要はありません。PHPの知識といくつかのタグで十分です。すべてはドキュメントで学ぶことができます。

テンプレートでは、他のPresenterとアクションへのリンクが作成されます。

<a n:href="Product:show $productId">製品詳細</a>

単に実際のURLの代わりに、既知の Presenter:action ペアを記述し、必要に応じてパラメータを指定します。トリックは n:href にあり、これはこの属性がNetteによって処理されることを示します。そして、次のように生成します。

<a href="/product/456">製品詳細</a>

URLの生成は、前述のルーターが担当します。Netteのルーターが例外的なのは、URLからPresenter:アクションのペアへの変換だけでなく、逆方向、つまりPresenter名+アクション+パラメータからURLを生成することもできることです。 これにより、NetteではテンプレートやPresenterの文字を1つも変更することなく、完成したアプリケーション全体のURL形式を完全に変更できます。ルーターを編集するだけで。 また、これにより、いわゆるカノニカル化が可能になります。これはNetteのもう1つのユニークな機能であり、異なるURLで重複コンテンツが存在するのを自動的に防ぐことで、より良いSEO(インターネットでの検索エンジンの最適化)に貢献します。 多くのプログラマーはこれを驚くべきことだと考えています。

インタラクティブコンポーネント

Presenterについてもう1つお伝えしなければならないことがあります:それらには組み込みのコンポーネントシステムがあります。DelphiやASP.NET Web Formsを知っている古い世代の方々には馴染みがあるかもしれません。ReactやVue.jsも、遠いながらも似たようなものに基づいています。PHPフレームワークの世界では、これは完全にユニークな機能です。

コンポーネントは、ページ(つまりPresenter)に挿入する独立した再利用可能なユニットです。フォームデータグリッド、メニュー、投票など、繰り返し使用する意味のあるものであれば何でもかまいません。独自のコンポーネントを作成したり、膨大な品揃えのオープンソースコンポーネントを使用したりできます。

コンポーネントは、アプリケーション開発へのアプローチに根本的な影響を与えます。事前に準備されたユニットからページを組み立てる新しい可能性を開きます。そして、さらにハリウッドと共通点があります。

DIコンテナと設定

DIコンテナ、またはオブジェクトファクトリは、アプリケーション全体の心臓部です。

心配しないでください。前の行からそう思われるかもしれませんが、これは魔法のブラックボックスではありません。実際には、Netteによって生成され、キャッシュディレクトリに保存される、かなり退屈なPHPクラスです。createServiceAbcd() のような名前の多くのメソッドがあり、それぞれがオブジェクトを作成して返すことができます。はい、createServiceApplication() メソッドもあり、これは index.php ファイルでアプリケーションを起動するために必要だった Nette\Application\Application を作成します。そして、個々のPresenterを作成するメソッドもあります。などなど。

DIコンテナが作成するオブジェクトは、何らかの理由でサービスと呼ばれます。

このクラスの本当に特別な点は、あなたがそれをプログラミングするのではなく、フレームワークがプログラミングすることです。それは実際にPHPコードを生成し、ディスクに保存します。あなたは、コンテナがどのオブジェクトを作成できるようにすべきか、そして具体的にどのように作成すべきかの指示を与えるだけです。そして、これらの指示は設定ファイルに書かれており、NEON形式が使用されるため、拡張子も .neon です。

設定ファイルは、純粋にDIコンテナに指示するために使用されます。したがって、例えばsessionセクションで expiration: 14 days オプションを指定すると、DIコンテナはセッションを表す Nette\Http\Session オブジェクトを作成するときに、その setExpiration('14 days') メソッドを呼び出し、それによって設定が現実になります。

設定できるすべてのことと、独自のサービスを定義する方法を説明する章全体が用意されています。

サービスの作成に少し慣れると、autowiringという言葉に出くわします。これは、信じられないほど人生を簡素化する機能です。何もする必要なく、必要な場所(例えばクラスのコンストラクタ)にオブジェクトを自動的に渡すことができます。NetteのDIコンテナが小さな奇跡であることに気づくでしょう。

次へ進むには?

Netteのアプリケーションの基本原則を見てきました。まだ非常に表面的ですが、すぐに深く掘り下げ、やがて素晴らしいWebアプリケーションを作成できるようになるでしょう。次にどこへ進むべきですか?最初のアプリケーションを作成するチュートリアルを試しましたか?

上記に加えて、Netteには便利なクラスの武器庫全体、データベースレイヤーなどがあります。ドキュメントをざっと見てみてください。またはブログをご覧ください。多くの興味深いことを見つけるでしょう。

フレームワークがあなたに多くの喜びをもたらしますように 💙

バージョン: 4.0