Nette Documentation Preview

syntax
Model
*****

アプリケーションが育つと、さまざまな場所やさまざまなプレゼンターで似たようなデータベースの操作をする必要があるとすぐ気づきます。たとえば最新の公開された記事を取り出すことなどです。アプリケーションを良くしようとして、たとえば記事が下書きかどうかを示す印を足したら、記事をデータベースから取り出しているすべての場所を見直して、下書きでない記事だけを選ぶ `where` の条件を足さなければなりません。

こうなると、データベースを直接扱うだけでは足りなくなり、公開された記事を返す新しいメソッドを使うほうが賢いやり方になります。そしてあとで別の条件(たとえば未来の日付の記事は表示しないなど)を足すときも、コードを 1 か所直すだけで済みます。

そのメソッドは `PostFacade` クラスに置き、`getPublicArticles()` と名付けます。

記事の面倒を見るモデルのクラス `PostFacade` を `app/Model/` のディレクトリに作ります。

```php .{file:app/Model/PostFacade.php}
<?php
namespace App\Model;

use Nette;

final class PostFacade
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}

	public function getPublicArticles()
	{
		return $this->database
			->table('posts')
			->where('created_at < ', new \DateTime)
			->order('created_at DESC');
	}
}
```

このクラスでは、データベースの [Explorer |api:Nette\Database\Explorer]をコンストラクタで求めています。これは [DI コンテナ |dependency-injection:passing-dependencies]の力を使っています。

では `HomePresenter` に移り、`Nette\Database\Explorer` への依存を取り除いて、新しいクラスへの依存に置き換えます。

```php .{file:app/Presentation/Home/HomePresenter.php}
<?php
namespace App\Presentation\Home;

use App\Model\PostFacade;
use Nette;

final class HomePresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private PostFacade $facade,
	) {
	}

	public function renderDefault(): void
	{
		$this->template->posts = $this->facade
			->getPublicArticles()
			->limit(5);
	}
}
```

`use` の区画に `App\Model\PostFacade` があるので、PHP のコードでは書き方を `PostFacade` と短くできます。このオブジェクトをコンストラクタで求め、`$facade` のプロパティに入れ、`renderDefault` メソッドで使います。

最後の一歩は、このオブジェクトを作るよう DI コンテナに教えることです。ふつうは `config/services.neon` ファイルの `services` の区画に項目を足し、完全なクラス名とコンストラクタのパラメータを指定します。これで登録され、そのオブジェクトは **サービス** と呼ばれます。[オートワイヤリング |dependency-injection:autowiring]の魔法のおかげで、たいていコンストラクタのパラメータを指定する必要はありません。DI がそれを見分けて自動的に渡すからです。ですからクラス名を書くだけで足ります。

```neon .{file:config/services.neon}
...

services:
	- App\Model\PostFacade
```

とはいえ、この行も足す必要はありません。`services.neon` の `search` の区画で、`-Facade` や `-Factory` で終わるすべてのクラスを DI が自動的に見つけると定められていて、`PostFacade` もそれに当てはまるからです。


まとめ
===

`PostFacade` クラスはコンストラクタで `Nette\Database\Explorer` を求め、このクラスは DI コンテナに登録されているので、コンテナがそのインスタンスを作って渡します。こうして DI は `PostFacade` のインスタンスを私たちの代わりに作り、それを求めた `HomePresenter` クラスのコンストラクタへ渡します。まるでマトリョーシカ人形です :) みんな欲しいものを言うだけで、それがどこでどう作られるかは気にしません。作るのは DI コンテナが受け持ちます。

.[note]
[dependency injection |dependency-injection:introduction]と[設定 |nette:configuring]については、こちらで詳しく読めます。

{{priority: -1}}

Model

アプリケーションが育つと、さまざまな場所やさまざまなプレゼンターで似たようなデータベースの操作をする必要があるとすぐ気づきます。たとえば最新の公開された記事を取り出すことなどです。アプリケーションを良くしようとして、たとえば記事が下書きかどうかを示す印を足したら、記事をデータベースから取り出しているすべての場所を見直して、下書きでない記事だけを選ぶ where の条件を足さなければなりません。

こうなると、データベースを直接扱うだけでは足りなくなり、公開された記事を返す新しいメソッドを使うほうが賢いやり方になります。そしてあとで別の条件(たとえば未来の日付の記事は表示しないなど)を足すときも、コードを 1 か所直すだけで済みます。

そのメソッドは PostFacade クラスに置き、getPublicArticles() と名付けます。

記事の面倒を見るモデルのクラス PostFacadeapp/Model/ のディレクトリに作ります。

<?php
namespace App\Model;

use Nette;

final class PostFacade
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}

	public function getPublicArticles()
	{
		return $this->database
			->table('posts')
			->where('created_at < ', new \DateTime)
			->order('created_at DESC');
	}
}

このクラスでは、データベースの Explorerをコンストラクタで求めています。これは DI コンテナの力を使っています。

では HomePresenter に移り、Nette\Database\Explorer への依存を取り除いて、新しいクラスへの依存に置き換えます。

<?php
namespace App\Presentation\Home;

use App\Model\PostFacade;
use Nette;

final class HomePresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private PostFacade $facade,
	) {
	}

	public function renderDefault(): void
	{
		$this->template->posts = $this->facade
			->getPublicArticles()
			->limit(5);
	}
}

use の区画に App\Model\PostFacade があるので、PHP のコードでは書き方を PostFacade と短くできます。このオブジェクトをコンストラクタで求め、$facade のプロパティに入れ、renderDefault メソッドで使います。

最後の一歩は、このオブジェクトを作るよう DI コンテナに教えることです。ふつうは config/services.neon ファイルの services の区画に項目を足し、完全なクラス名とコンストラクタのパラメータを指定します。これで登録され、そのオブジェクトは サービス と呼ばれます。オートワイヤリングの魔法のおかげで、たいていコンストラクタのパラメータを指定する必要はありません。DI がそれを見分けて自動的に渡すからです。ですからクラス名を書くだけで足ります。

...

services:
	- App\Model\PostFacade

とはいえ、この行も足す必要はありません。services.neonsearch の区画で、-Facade-Factory で終わるすべてのクラスを DI が自動的に見つけると定められていて、PostFacade もそれに当てはまるからです。

まとめ

PostFacade クラスはコンストラクタで Nette\Database\Explorer を求め、このクラスは DI コンテナに登録されているので、コンテナがそのインスタンスを作って渡します。こうして DI は PostFacade のインスタンスを私たちの代わりに作り、それを求めた HomePresenter クラスのコンストラクタへ渡します。まるでマトリョーシカ人形です :) みんな欲しいものを言うだけで、それがどこでどう作られるかは気にしません。作るのは DI コンテナが受け持ちます。

dependency injection設定については、こちらで詳しく読めます。