このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン 前のリビジョン 次のリビジョン | 前のリビジョン | ||
apricot:usage:ja:controller [2020/08/03 14:51] tanaka [Apricot コントローラ] |
apricot:usage:ja:controller [2020/09/03 13:46] y2sunlight [Apricot コントローラ] |
||
---|---|---|---|
行 1: | 行 1: | ||
- | > 編集中 | ||
- | |||
- | ---- | ||
- | |||
====== Apricot コントローラ ====== | ====== Apricot コントローラ ====== | ||
--- // | --- // | ||
- | [[apricot: | + | [[apricot: |
目次 | 目次 | ||
+ | * [[apricot: | ||
* [[apricot: | * [[apricot: | ||
* [[apricot: | * [[apricot: | ||
* [[apricot: | * [[apricot: | ||
* [[apricot: | * [[apricot: | ||
- | * [[apricot: | + | * [[apricot: |
+ | * [[apricot: | ||
* [[apricot: | * [[apricot: | ||
* Apricot コントローラ | * Apricot コントローラ | ||
+ | * [[apricot: | ||
+ | * [[apricot: | ||
+ | * [[apricot: | ||
* [[apricot: | * [[apricot: | ||
---- | ---- | ||
- | ===== ルーティングとコントローラ(Auto Wiring) ===== | + | 本章では主にApricotのスケルトンに含まれているユーザコントローラを例にとって説明します。ユーザコントローラは、以下に配置されています。 |
- | >TODO | + | |
+ | < | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ===== ルーティング | ||
+ | |||
+ | リクエストルータは、アプリケーションのエンドポイント(URI)がどの コントローラ@アクション を実行するのかを決定します。Apricotでは、リクエストルータに FastRouteを使用しています。ルーティングに関する詳細は [[https:// | ||
+ | |||
+ | ルーティングの設定は、''/ | ||
+ | |||
+ | {{fa> | ||
+ | <code php routes.php> | ||
+ | <?php | ||
+ | /** | ||
+ | * This file contains callback for route definitions. | ||
+ | */ | ||
+ | return function (FastRoute\RouteCollector $r) | ||
+ | { | ||
+ | /** @var string $base route base path */ | ||
+ | $base = Apricot\Application:: | ||
+ | |||
+ | // Creates a route group with a common prefix. | ||
+ | $r-> | ||
+ | { | ||
+ | // An example | ||
+ | $r-> | ||
+ | }); | ||
+ | }; | ||
+ | </ | ||
+ | |||
+ | '' | ||
+ | |||
+ | '' | ||
+ | |||
+ | 上の例では、getメソッドに対する特定のルート( ''/ | ||
+ | |||
+ | ハンドラーには以下の例のように、クロージャ―を使用するできます。この例では、利用者が ''/ | ||
+ | |||
+ | <code php> | ||
+ | $r->get(' | ||
+ | header(" | ||
+ | }); | ||
+ | </ | ||
+ | |||
+ | 以下は、ユーザ登録ページの CRUD操作(create, | ||
+ | |||
+ | <code php> | ||
+ | <?php | ||
+ | $r->get ('/ | ||
+ | $r->get ('/ | ||
+ | $r-> | ||
+ | $r->get ('/ | ||
+ | $r-> | ||
+ | $r-> | ||
+ | }; | ||
+ | </ | ||
+ | |||
+ | フォームから送信される場合はpostメソッドが、それ以外はgetメソッドのルートが定義されています。indexアクションはユーザリスト表示、createアクションは新規登録ページ、editアクションは編集ページを表示します。insert、update そして deleteのアクション はそれぞれCUD操作を実行します。 | ||
+ | |||
+ | editアクションなどのルートは名前付きのプレースホルダーを '' | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ===== コントローラとアクション ===== | ||
+ | |||
+ | ルーティングによって設定されているエンドポイント(URI)がアクセスされると、Apricotはハンドラー(クロージャでない場合)で指定されている '' | ||
+ | |||
+ | < | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | 以下は、Apricotのスケルトンに含まれているHomeコントローラです。このコントローラにはindexアクションだけが含まれています。 | ||
+ | |||
+ | {{fa> | ||
+ | <code php HomeController.php> | ||
+ | <?php | ||
+ | namespace App\Controllers; | ||
+ | |||
+ | use App\Foundation\Controller; | ||
+ | use App\Foundation\Security\AuthUser; | ||
+ | |||
+ | /** | ||
+ | * Home Controller | ||
+ | */ | ||
+ | class HomeController extends Controller | ||
+ | { | ||
+ | /** | ||
+ | * Index Page for this controller. | ||
+ | * | ||
+ | * @return \Apricot\Foundation\Response | ||
+ | */ | ||
+ | public function index() | ||
+ | { | ||
+ | $message = __(' | ||
+ | return render(' | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ==== コンストラクター ==== | ||
+ | |||
+ | 以下は、ユーザコントローラのコンストラクタです。 | ||
+ | |||
+ | <code php> | ||
+ | /** | ||
+ | * User Controller | ||
+ | */ | ||
+ | class UserController extends Controller | ||
+ | { | ||
+ | /** | ||
+ | * @var \App\Models\User | ||
+ | */ | ||
+ | private $user; | ||
+ | |||
+ | /** | ||
+ | * Creates a user controller. | ||
+ | */ | ||
+ | public function __construct(User $user) | ||
+ | { | ||
+ | // User Model | ||
+ | $this-> | ||
+ | |||
+ | // Registers interceptors. | ||
+ | $this-> | ||
+ | $this-> | ||
+ | |||
+ | // Registers transactional actions. | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | // ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | === Auto Wiring | ||
+ | |||
+ | < | ||
+ | public function __construct(User $user) | ||
+ | </ | ||
+ | |||
+ | コントローラのコンストラクタは、Auto Wiring をサポートします。これは、コンストラクター引数の型ヒントを調べることにより、オブジェクトとそのすべての依存関係を再帰的に自動的に解決する機能です。但し、注入できるのはオブジェクト型の変数だけです。Auto Wiring には外部ライブラリーの [[https:// | ||
+ | |||
+ | Auto Wiring で使用する引数には、一般的にモデルクラスやサービスクラスを指定します。上の例では、ユーザモデルをコンストラクター引数に指定し、それをメンバ変数( '' | ||
+ | |||
+ | === インターセプターの登録 | ||
+ | |||
+ | <code php> | ||
+ | $this-> | ||
+ | $this-> | ||
+ | </ | ||
+ | |||
+ | コンストラクタではアクションに[[# | ||
+ | |||
+ | === トランザクションの適用 === | ||
+ | |||
+ | <code php> | ||
+ | $this-> | ||
+ | </ | ||
+ | |||
+ | コンストラクタではアクションに[[# | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ==== アクション ==== | ||
+ | |||
+ | 以下はユーザコントローラのeditアクションの例です。 | ||
+ | |||
+ | <code php> | ||
+ | public function edit(int $id) | ||
+ | { | ||
+ | // Finds By the primary key | ||
+ | $user = $this-> | ||
+ | if ($user!==false) | ||
+ | { | ||
+ | return render(" | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | return redirect(route(" | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | '' | ||
+ | |||
+ | <code php> | ||
+ | get('/ | ||
+ | </ | ||
+ | |||
+ | 例えば、利用者が ''/ | ||
\\ | \\ | ||
===== インターセプター ===== | ===== インターセプター ===== | ||
- | >TODO | + | |
+ | インターセプター とはアクションの前処理の事です。ミドルウェアと同じでリクエストを中断してレスポンスオブジェクトを生成することもできますが、アクションの後処理はできません。これを図示すると以下のようになります。 | ||
+ | |||
+ | === インターセプター構造 === | ||
+ | |||
+ | {{: | ||
+ | |||
+ | 上図から分かるようにミドルウェアパイプラインから見ると、インターセプターはアクションに含まれます。ミドルウェアとの一番の違いは、ミドルウェアは基本的に全てのコントローラを対象としているのに対し、インターセプターは、各コントローラで独自に設定ができるという点です。 | ||
+ | |||
+ | インターセプターの主な用途としては以下のものがあります: | ||
+ | |||
+ | * 入力データの検証(バリデーション) | ||
+ | * 不要な入力データの除去 | ||
+ | * 入力データの変換 | ||
+ | |||
+ | インターセプターを利用することで、簡潔なアクションを作ることができます。 | ||
\\ | \\ | ||
- | ===== バリデーション ===== | + | ==== インターセプターの登録 |
- | >TODO | + | |
+ | インターセプターの登録は、コントローラーのコンストラクタの中でコントローラーの '' | ||
+ | |||
+ | <code php> | ||
+ | class FooController extends Controller | ||
+ | { | ||
+ | public function __construct() | ||
+ | { | ||
+ | // インターセプターの登録 | ||
+ | $this-> | ||
+ | { | ||
+ | $inputs | ||
+ | // バリデーション処理 | ||
+ | }); | ||
+ | } | ||
+ | ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | インターセプターに渡される引数は、第1引数に、コントローラのインスタンスが、その後にアクションと同じの引数が続きます。また、インターセプターはレスポンスオブジェクトを返して以降のアクションを中止することができます。 | ||
+ | |||
+ | インターセプターに< | ||
+ | |||
+ | <code php> | ||
+ | class FooController extends Controller | ||
+ | { | ||
+ | public function __construct(User $user) | ||
+ | { | ||
+ | // インターセプター登録 | ||
+ | $this-> | ||
+ | $this-> | ||
+ | ... | ||
+ | } | ||
+ | .... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | インターセプターとして自分自身( $this )のメソッドを指定する場合は、''< | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ==== インターセプターの作成 | ||
+ | |||
+ | インターセプターは以下の場所に配置する必要があります( 名前空間は '' | ||
+ | |||
+ | <code> | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | インターセプターメソッドのシグネチャには次の規則があります: | ||
+ | |||
+ | <code php> | ||
+ | /** | ||
+ | * Interceptor method | ||
+ | * | ||
+ | * @param Controller $controller インターセプターを呼び出したコントローラ | ||
+ | * @param mixed $... 対応するアクションメソッドと同じ引数 | ||
+ | * @return void|\Apricot\Foundation\Response 失敗の場合Responseオブジェクトを返す | ||
+ | */ | ||
+ | public function interceptorMethod( Controller $controller, | ||
+ | </ | ||
+ | |||
+ | 以下にユーザコントローラのinsertアクションに対するインターセプター( UserInterceptor@insert )の例を示します。 | ||
+ | |||
+ | {{fa> | ||
+ | <code php UserInterceptor.php> | ||
+ | <?php | ||
+ | namespace App\Controllers\Interceptors; | ||
+ | |||
+ | use Apricot\Input; | ||
+ | use App\Foundation\Controller; | ||
+ | use App\Foundation\ValidatorErrorBag; | ||
+ | |||
+ | /** | ||
+ | * User Interceptor | ||
+ | */ | ||
+ | class UserInterceptor | ||
+ | { | ||
+ | /** | ||
+ | * Interceptor for insert method. | ||
+ | * | ||
+ | * @return void|\Apricot\Foundation\Response return Response if failed | ||
+ | */ | ||
+ | public function insert(Controller $controller) | ||
+ | { | ||
+ | $inputs = Input:: | ||
+ | |||
+ | // Validation | ||
+ | $v =(new \Valitron\Validator($inputs)); | ||
+ | -> | ||
+ | -> | ||
+ | -> | ||
+ | |||
+ | if(!$v-> | ||
+ | { | ||
+ | $errorBag = new ValidatorErrorBag($v-> | ||
+ | return redirect(back())-> | ||
+ | } | ||
+ | |||
+ | // Removes unnecessary inputs | ||
+ | Input:: | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | この例では、Input:: | ||
+ | |||
+ | バリデーションが失敗した時、withInputs() で入力変数を、withErrors() で[[apricot: | ||
+ | |||
+ | バリデーションが成功した時、不要になった入力変数 ' | ||
\\ | \\ | ||
===== トランザクション ===== | ===== トランザクション ===== | ||
- | >TODO | + | |
+ | Apricotでは、コントローラのアクションをラップする形で、アクションにトランザクションを適用することができます。Apricotは、トランザクションの適用されたアクションを呼び出す前にトランザクションを開始し、アクションが正常に終了するとそのトランザクションをコミットします。アクションが '' | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ==== トランザクションの適用 ==== | ||
+ | |||
+ | アクションにトランザクションを適用するには、以下のように、コンストラクターの中で、コントローラの '' | ||
+ | |||
+ | <code php> | ||
+ | class FooController extends Controller | ||
+ | { | ||
+ | public function __construct(User $user) | ||
+ | { | ||
+ | // トランザクションの適用 | ||
+ | $this-> | ||
+ | ... | ||
+ | } | ||
+ | .... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | この例では、insert、updateそしてdeteleの各アクションにトランザクションを適用しています。このように、'' | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ==== トランザクションの処理 ==== | ||
+ | |||
+ | 以下は、ユーザコントローラの update アクションの例です。 | ||
+ | |||
+ | <code php> | ||
+ | /** | ||
+ | * Updates a user record. | ||
+ | * | ||
+ | * @param int $id | ||
+ | * @return \Apricot\Foundation\Response | ||
+ | */ | ||
+ | public function update(int $id) | ||
+ | { | ||
+ | $inputs = Input:: | ||
+ | |||
+ | try | ||
+ | { | ||
+ | $this-> | ||
+ | } | ||
+ | catch(ApplicationException $e) | ||
+ | { | ||
+ | throw $e; | ||
+ | } | ||
+ | catch(\Exception $e) | ||
+ | { | ||
+ | throw new ApplicationException(__(' | ||
+ | } | ||
+ | |||
+ | // Redirects to the user edit page. | ||
+ | return redirect(route(" | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | この例では、ユーザモデル( < | ||
+ | |||
+ | アクションがしなければならないことは、モデルの例外を捕捉して、ApplicationException をスローすることだけです。フレームワークは ApplicationException またはそれを親に持つ例外のみを捕捉します。それ以外の例外は、集約エラーハンドラーによって補足されシステムエラーになります。即ち、フレームワークは、ApplicationException のみ前画面に戻すリダイレクトレスポンスを生成します。 | ||
+ | |||
+ | モデルは次の場合に ApplicationException をスローします: | ||
+ | |||
+ | * 楽観的ロック例外が発生した場合( '' | ||
+ | * 対象レコードが存在しない場合(レコード更新時および削除時) | ||
+ | |||
+ | アクションでは、これ以外の例外が発生した場合は、パースエラーなどの '' | ||
+ | |||
+ | === クエリーの例外処理 === | ||
+ | |||
+ | 通常、トランザクションは更新系の処理で設定するするので、クエリーで発生した全ての例外は集約エラーハンドラで処理されエラー画面が表示されます。この状況を避けたい場合は、次の何れかの選択になるでしょう。 | ||
+ | |||
+ | * クエリーのアクションにもトランザクションを設定する | ||
+ | * アクション内のcatchブロックでエラーメッセージ付きの入力ページをレンダリングする | ||
\\ | \\ | ||