内容へ移動
Ground Sunlight
Windowsで作る - PHPプログラミングの開発環境
ユーザ用ツール
ログイン
サイト用ツール
検索
ツール
文書の表示
以前のリビジョン
バックリンク
最近の変更
メディアマネージャー
サイトマップ
ログイン
>
最近の変更
メディアマネージャー
サイトマップ
トレース:
•
メインメニュー
•
WSL2 ディストリビューションの複製
•
Mroonga
apricot:ext:di-container
この文書は読取専用です。文書のソースを閲覧することは可能ですが、変更はできません。もし変更したい場合は管理者に連絡してください。
====== Apricot DIコンテナー ====== --- //[[http://www.y2sunlight.com|y2sunlight]] 2020-05-25// [[apricot:top|Apricot に戻る]] 関連記事 * [[apricot:configuration|Apricot プロジェクトの作成]] * [[apricot:public|Apricot 公開フォルダ]] * [[apricot:core:top|Apricot コア]] * [[apricot:app:top|Apricot アプリ]] * Apricot 拡張 * [[apricot:ext:middleware|Apricot ミドルウェア]] * [[apricot:ext:access-log|Apricot アクセスログ]] * [[apricot:ext:csrf|Apricot CSRF対策]] * [[apricot:ext:user-auth|Apricot ユーザ認証]] * [[apricot:ext:basic-auth|Apricot 基本認証]] * [[apricot:ext:session-auth|Apricot セッション認証]] * [[apricot:ext:interceptor|Apricot インターセプター]] * Apricot DIコンテナー ApricotではDIコンテナーに[[basic-library:league-container:3.3|League/Container]]を採用します。主な用途はコントローラに対する ''Auto Wiring'' です。''Auto Wiring'' とはコンストラクター引数の型ヒントを調べることにより、オブジェクトとそのすべての依存関係を再帰的に自動的に解決する機能の事です。地味な機能ですが、保守性向上の為、コンストラクター・インジェクションは必須と考えて実装することにしました。 また、DIコンテナーを使って、サービスプロバイターの仕組みも実装します。この機能については現版のApricotでは使用する場面が無かったので、スタブコントローラの中に例題をつくりました。 尚、DIコンテナーに関する設定ファイル( ''config/setting/container.setting.php'' )や初期設定ファイル( ''config/setup/container.setup.php'' )は今のところありません。カスタマイズの際は必要に応じて追加して下さい。 ---- ===== コントローラの Auto Wiring ===== 以下は、現状のユーザコントローラのコンストラクタです。 <code php> public function __construct() { // モデル $this->user = new User(); ... } </code> このコードを ''Auto Wiring'' によって、次のようにすることがここでの目的です。 <code php> public function __construct(User $user) { // モデル $this->user = $user; ... } </code> ''Auto Wiring'' は、コンストラクタの型ヒントによって生成するオブジェクトを判断します。(オブジェクト型でない引数には対応していません) \\ ==== ActionInvokerクラス ==== コントローラを生成( new )しているのは、ActionInvoker クラスの invoke() メソッドです。このメソッドを以下のように変更します。 {{fa>folder-open-o}} ** /apricot/core/Foundation ** <code php ActionInvoker.php> <?php namespace Core\Foundation; /** * Request ActionInvoker Class */ class ActionInvoker implements Invoker { .... /** * Invoke action * {@inheritDoc} * @see \Core\Foundation\Invoker::invoke() */ public function invoke() : Response { // Enable auto wiring $container = new \League\Container\Container; $container->delegate(new \League\Container\ReflectionContainer); // Get controller instance $instance = $container->get("\\App\\Controllers\\{$this->controller}"); return call_user_func_array(array($instance, 'invokeAction'), [$this->action, $this->params]); } } </code> * コンテナデリゲートとして ReflectionContainer を登録し ''Auto Wiring'' を有効にします。 * コントローラの生成を 単純なnew演算子から Container の get()メソッドに変更します。 Containerの使い方については、[[basic-library:league-container:3.3|League/Container]]を参照して下さい。 \\ ==== ユーザコントローラ ==== ユーザコントローラ (UserController )のコンストラクタを[[#コントローラの Auto Wiring|上]]で述べたように以下のように変更して下さい。 {{fa>folder-open-o}} ** /apricot/app/Controllers ** <code php UserController.php> <?php namespace App\Controllers; use App\Exceptions\ApplicationException; use App\Foundation\Controller; use App\Models\User; use Core\Input; /** * ユーザコントローラ */ class UserController extends Controller { /** * User * @var \App\Models\User */ private $user; /** * ユーザコントローラの生成 */ public function __construct(User $user) { // モデル $this->user = $user; // インターセプター登録 $this->intercept('insert', 'UserInterceptor@insert'); $this->intercept('update', 'UserInterceptor@update'); // トランザクションアクション登録 $this->transactional('insert','update','delete'); } ... } </code> 修正が終わったら、Apricotのユーザ一覧画面や編集画面を操作して動作確認をして見て下さい。 \\ ===== サービスプロバイター ===== サービスコンテナを使用することで、サービスとサービス間の依存関係を登録しておいて後で取得することができます。例えば、サービスAがモデルBとモデルCを使用しているような場合、サービスコンテナにサービスAを要求すると、自動的にモデルBとCを生成し、それらをサービスAのコンストラクタに与えてサービスAを生成してくれます。 サービスプロバイターは、アプリケーション内の全てのサービスコンテナを登録し整理する方法を提供してくれます。また、サービスプロバイダーではサービスが取得された時点で遅延登録されるため、アプリケーションのパフォーマンス向上にも寄与します。 League/Container でサービスプロバイダーを構築するには以下のステップに従います。 - League/Container の 基本サービスプロバイダークラス( ''AbstractServiceProvider'' )を拡張して 独自のサービスプロバイダーを作ります。 - League/Container の ''Container'' クラスに 独自のサービスプロバイダーを登録します。 Apricotでは、独自のサービスプロバイダーとして ''App\Provider'' クラスを定義し、それを登録する ''App\Foundation\Container'' クラスをシングルトンとして実装します。サービスの使用者は、''App\Foundation\Container''が持っている [[https://www.php-fig.org/psr/psr-11/|PSR-11]] に準じた ''get()'' と ''has()'' を使ってサービスを利用することができます。 \\ ==== Providerクラス ==== 以下に、League/Container の 基本サービスプロバイダークラス( AbstractServiceProvider )を拡張したApricot独自のサービスプロバイダークラス( Provider )を以下に示します。 {{fa>folder-open-o}} ** /apricot/app ** <code php Provider.php> <?php namespace App; use League\Container\ServiceProvider\AbstractServiceProvider; /** * Provider class for service */ class Provider extends AbstractServiceProvider { /** * The provided array is a way to let the container * know that a service is provided by this service * provider. Every service that is registered via * this service provider must have an alias added * to this array or it will be ignored. * * @var array */ protected $provides = [ // Example 'user', ]; /** * This is where the magic happens, within the method you can * access the container and register or retrieve anything * that you need to, but remember, every alias registered * within this method must be declared in the `$provides` array. */ public function register() { // Example $this->getContainer()->add('user', \App\Models\User::class ); } } </code> このクラスは、名前空間Appの直下に存在し、アプリケーションのモデル及びサービスのマップを提供します。現版のApricotでは、モデルはユーザモデル( User )だけで、サービスについては存在しません。モデルやサービスを追加する場合は、上例に習って適宜追加して下さい。 現版のApricotでは、サービスは存在しませんが、サービス用として以下のフォルダが予約されています。 <code> /apricot/app/Services </code> 尚、League/Container のサービスプロバイダーについての詳細は[[https://container.thephpleague.com/3.x/service-providers/|こちら]]をご覧ください。 \\ ==== App\Foundation\Containerクラス ==== App\Foundation\Containerクラスは、\League\Container\Container クラスを生成し、Apricotのサービスプロバイダー(Provider)を登録したクラスで、シングルトンとして動作します。 使用法: ** Container::{メソッド} ** ^メソッド^機能^ |mixed get(string $id)|識別子idでコンテナのエントリを検索して返します。| |bool has(string $id)|コンテナが指定された識別子idのエントリを返すことができる場合はtrueを返します。| {{fa>folder-open-o}} ** /apricot/app/Foundation ** <code php Container.php> <?php namespace App\Foundation; use Core\Foundation\Singleton; use App\Provider; /** * Container class for service * * @method static Container getInstance(); * @method static mixed get(string $id) Finds an entry of the container by its identifier and returns it. * @method static bool has(string $id) Returns true if the container can return an entry for the given identifier. */ class Container extends Singleton { /** * Create Container instance. * @return \League\Container\Container */ protected static function createInstance() { $container = new \League\Container\Container; $container->addServiceProvider(new Provider()); return $container; } } </code> \\ ==== サービスコンテナの使用例 ==== === スタブコントローラ === サービスコンテナをテストするために、スタブコントローラを以下のように修正します。 {{fa>folder-open-o}} ** /apricot/app/Controllers ** <code php StubController.php> namespace App\Controllers; use App\Foundation\Container; use App\Foundation\Controller; /** * Stubコントローラ */ class StubController extends Controller { /** * Stub Page * @return \Core\Foundation\Response */ public function index(int $no=null) { $title = "Stub {$no}"; /* * Example for Container * @var \App\Models\User $user */ $user = Container::get('user'); $userCount = count($user->findAll()); $messages[] = "Number of registered users : {$userCount}"; return render('stub',['title'=>$title,'messages'=>$messages]); } } </code> * ''Container::get('user')'' でユーザモデルを生成します。 * ユーザモデルの ''findAll()'' を実行して全ユーザのリストを取得します。 * ユーザ数を表示するために、テンプレート変数 ''$messages'' をセットします。 \\ === テスト実行 === Apricotのホーム画面を表示して、[Menu2]をクリックして下さい。 [{{apricot:ext:ext09.png?nolink}}] ■ 画面にユーザ数が表示されます <code> Number of registered users : 2 </code> \\ \\
apricot/ext/di-container.txt
· 最終更新: 2020/05/26 16:42 by
y2sunlight
ページ用ツール
文書の表示
以前のリビジョン
バックリンク
文書の先頭へ