このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン 前のリビジョン 次のリビジョン | 前のリビジョン 次のリビジョン 両方とも次のリビジョン | ||
apricot:usage:ja:controller [2020/08/03 14:51] tanaka [Apricot コントローラ] |
apricot:usage:ja:controller [2020/08/05 12:15] tanaka [ルーティング] |
||
---|---|---|---|
行 6: | 行 6: | ||
--- // | --- // | ||
- | [[apricot: | + | [[apricot: |
目次 | 目次 | ||
+ | * [[apricot: | ||
* [[apricot: | * [[apricot: | ||
* [[apricot: | * [[apricot: | ||
行 22: | 行 23: | ||
===== ルーティングとコントローラ(Auto Wiring) ===== | ===== ルーティングとコントローラ(Auto Wiring) ===== | ||
- | >TODO | + | |
+ | ==== ルーティング ==== | ||
+ | |||
+ | 以下のように、config/ | ||
+ | |||
+ | {{fa>folder-open-o}} ** / | ||
+ | <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-> | ||
+ | { | ||
+ | // Authentication | ||
+ | $r->get ('/ | ||
+ | $r-> | ||
+ | $r->get ('/ | ||
+ | |||
+ | // User | ||
+ | $r->get ('/ | ||
+ | $r->get ('/ | ||
+ | $r-> | ||
+ | $r->get ('/ | ||
+ | $r-> | ||
+ | $r-> | ||
+ | |||
+ | // Home | ||
+ | $r->get ('/ | ||
+ | $r-> | ||
+ | header(" | ||
+ | }); | ||
+ | |||
+ | // Stub | ||
+ | $r-> | ||
+ | }); | ||
+ | }; | ||
+ | </ | ||
+ | |||
+ | ルーティング設定に関しては[[https:// | ||
+ | \\ | ||
+ | |||
+ | ==== コントローラ ==== | ||
+ | |||
+ | 上述のアプリ用のコントローラベースを継承してスタブコントローラを作ります。 | ||
+ | |||
+ | {{fa> | ||
+ | <code php StubController.php> | ||
+ | <?php | ||
+ | namespace App\Controllers; | ||
+ | |||
+ | use App\Foundation\Controller; | ||
+ | |||
+ | /** | ||
+ | * Stubコントローラ | ||
+ | */ | ||
+ | class StubController extends Controller | ||
+ | { | ||
+ | /** | ||
+ | * Stub Page | ||
+ | * @return \Core\Foundation\Response | ||
+ | */ | ||
+ | public function index(int $no=null) | ||
+ | { | ||
+ | $title = "Stub {$no}"; | ||
+ | $messages = []; | ||
+ | |||
+ | return render(' | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | * スタブコントローラにindexアクションを実装してる例です | ||
+ | * ボイラープレートのrender()関数を呼び出してレスポンスをレンダリングしています | ||
+ | * **render(string $view=null, array $variables=[])** | ||
+ | - $view : テンプレート名\\ 上例では assets/ | ||
+ | - $variables : テンプレート変数の連想配列\\ 上例では [$title, | ||
+ | |||
+ | \\ | ||
+ | |||
+ | |||
+ | ==== Auto Wiring ==== | ||
+ | |||
+ | 以下は、現状のユーザコントローラのコンストラクタです。 | ||
+ | |||
+ | <code php> | ||
+ | public function __construct() | ||
+ | { | ||
+ | // モデル | ||
+ | $this-> | ||
+ | ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | このコードを '' | ||
+ | |||
+ | <code php> | ||
+ | public function __construct(User $user) | ||
+ | { | ||
+ | // モデル | ||
+ | $this-> | ||
+ | ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | '' | ||
+ | |||
+ | \\ | ||
\\ | \\ | ||
===== インターセプター ===== | ===== インターセプター ===== | ||
- | >TODO | + | |
+ | インターセプター とはアクションの前処理の事です。ミドルウェアと同じでリクエストを中断してレスポンスオブジェクトを生成することもできますが、アクションの後処理はできません。これを図示すると以下のようになります。 | ||
+ | |||
+ | === インターセプター構造 === | ||
+ | |||
+ | {{: | ||
+ | |||
+ | 上図から分かるようにミドルウェアパイプラインから見ると、インターセプターはアクションに含まれます。ミドルウェアとの一番の違いは、ミドルウェアは基本的に全てのコントローラを対象としているのに対し、インターセプターは、各コントローラで独自に設定ができるという点です。 | ||
+ | |||
+ | インターセプターの主な用途としては入力データの検証(バリデーション)、入力データのフィルタリングや変換です。インターセプターを作ることで、すっきりしたアクションを作ることができます。 | ||
+ | |||
+ | ==== インターセプターの使用 ==== | ||
+ | |||
+ | インターセプターの登録は、コントローラーのコンストラクタで '' | ||
+ | |||
+ | <code php> | ||
+ | class FooController extends Controller | ||
+ | { | ||
+ | public function __construct() | ||
+ | { | ||
+ | // インターセプターの登録 | ||
+ | $this-> | ||
+ | { | ||
+ | $inputs = Input:: | ||
+ | ... | ||
+ | }); | ||
+ | } | ||
+ | ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | インターセプターに渡される引数は、第1引数に、コントローラのインスタンスが、その後にアクションと同じの引数が続きます。また、インターセプターはレスポンスオブジェクトを返して以降のアクションを中止することができます。 | ||
+ | |||
+ | インターセプターにメソッド型を使用する場合は、以下のように < | ||
+ | |||
+ | <code php> | ||
+ | class FooController extends Controller | ||
+ | { | ||
+ | public function __construct(User $user) | ||
+ | { | ||
+ | // インターセプター登録 | ||
+ | $this-> | ||
+ | $this-> | ||
+ | ... | ||
+ | } | ||
+ | .... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Apricotでは、インターセプターを配置する場所は以下に決めれられいます。 | ||
+ | < | ||
+ | aprocot/ | ||
+ | </ | ||
+ | |||
+ | 結果として、インターセプタークラスの名前空間は '' | ||
+ | |||
+ | 自分自身( $this )のメソッドを指定する場合は、''< | ||
\\ | \\ | ||
===== バリデーション ===== | ===== バリデーション ===== | ||
- | >TODO | + | |
+ | Apricotでは Valitron を使いサーバ側のバリデーションで使用します。以下では、Valitron の設定方法について述べます。詳細は [[https:// | ||
+ | |||
+ | ==== 言語ファイル ==== | ||
+ | |||
+ | Valitronの言語ファイルを以下の手順でカスタマイズします。 | ||
+ | |||
+ | |||
+ | - '' | ||
+ | * '' | ||
+ | - コピーした '' | ||
+ | |||
+ | {{fa>folder-open-o}} ** / | ||
+ | <code php vlucas.valitron.php> | ||
+ | <?php | ||
+ | |||
+ | return array( | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ); | ||
+ | </ | ||
+ | |||
+ | * ''' | ||
+ | * ''' | ||
\\ | \\ | ||
+ | |||
+ | ==== uniqueルール ==== | ||
+ | |||
+ | uniqueルールはデーターベースのユニーク制約の為のルールです。 | ||
+ | |||
+ | 使用法: **rule(' | ||
+ | |||
+ | * $unique_column_name --- ユニークカラム名 | ||
+ | * $table_name --- テーブル名 | ||
+ | * $id_column_name --- IDカラム名 | ||
+ | |||
+ | <code php> | ||
+ | // 使用例 | ||
+ | $validator = new \Valitron\Validator($inputs); | ||
+ | $validator-> | ||
+ | </ | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ==== ValidatorErrorBagクラス ==== | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ==== 使用例:ユーザインターセプター ==== | ||
+ | |||
+ | インターセプターメソッドのシグネチャには次の規則があります: | ||
+ | |||
+ | * **interceptorMethod( Controller $controller, | ||
+ | - $controller --- インターセプターを呼び出したコントローラ | ||
+ | - $... --- インターセプターを呼び出したアクションメソッドと同じ引数 | ||
+ | * 戻り値 | ||
+ | - 成功の場合 --- void を返す | ||
+ | - 失敗の場合 --- Responseオブジェクトを返す | ||
+ | |||
+ | 以下にユーザインターセプター( UserInterceptor )を示します。 | ||
+ | |||
+ | {{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:: | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Interceptor for update method. | ||
+ | * | ||
+ | * @param int $id | ||
+ | * @return void|\Apricot\Foundation\Response return Response if failed | ||
+ | */ | ||
+ | public function update(Controller $controller, | ||
+ | { | ||
+ | $inputs = Input:: | ||
+ | |||
+ | // Validation | ||
+ | $v =(new \Valitron\Validator($inputs)) | ||
+ | -> | ||
+ | -> | ||
+ | -> | ||
+ | -> | ||
+ | |||
+ | if(!$v-> | ||
+ | { | ||
+ | $errorBag = new ValidatorErrorBag($v-> | ||
+ | return redirect(back())-> | ||
+ | } | ||
+ | |||
+ | // Removes unnecessary inputs | ||
+ | Input:: | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | バリデーションの手順は以下の通りです。 | ||
+ | |||
+ | - Input:: | ||
+ | - Validatorの生成 | ||
+ | * rule()メソッドで検証ルールを適用します | ||
+ | * labels()メソッドでエラーメッセージで使う項目名を設定します | ||
+ | - Validatorのvalidate()メソッドで検証します | ||
+ | * 検証エラーの時 | ||
+ | * withInputs()で入力変数をフラッシュ変数に保存します | ||
+ | * withErrors()でバリデーションのエラーバッグをフラッシュ変数に保存します | ||
+ | * redirect()で前画面にリダイレクトするResponseオブジェクトをします | ||
+ | * 検証成功の時 | ||
+ | * 不要になったバリデーション用のフォームデータを削除します | ||
+ | |||
+ | === 検証ルール === | ||
+ | |||
+ | * **insert()** : レコード挿入時\\ | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | * **update()** : レコード更新時\\ | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | \\ | ||
+ | |||
===== トランザクション ===== | ===== トランザクション ===== | ||
- | >TODO | + | |
+ | ユーザ登録画面にトランザクションの機能を追加します。トランザクションを作るか否かはアクション毎に設定できるようにします。また、トランザクション機能を追加することによりアクションでスローされる ApplicationException をキャッチして(エラー画面に遷移することなく)入力画面でエラーメッセージを表示できるようになります。アクションでスローされるApplicationException には以下のものがあります。 | ||
+ | |||
+ | * 楽観的ロック例外(OptimissticLockException) | ||
+ | * 対象レコードが存在しない(レコード更新時および削除時) | ||
+ | * その他のアクションで発生する'' | ||
+ | |||
+ | 通常、トランザクションは更新系の処理で設定するするので、参照系で発生した全ての例外は集約エラーハンドラで処理されエラー画面が表示されます。この状況を避けたい場合は、次の何れかの選択になるでしょう。 | ||
+ | |||
+ | * 参照系アクションもトランザクションを設定する | ||
+ | * アクション内のcatchブロックでエラーメッセージ付きの入力画面をレンダリングする | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ==== 使用例:ユーザコントローラ ==== | ||
+ | |||
+ | アクションのトランザクション処理を有効にしたい場合は、コントローラのコンストラクタの中でControllerクラスのtransactional()メソッドを使って、以下のようにします。 | ||
+ | |||
+ | * **transactional( ' | ||
+ | |||
+ | {{fa>folder-open-o}} ** / | ||
+ | <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 | ||
+ | { | ||
+ | ... | ||
+ | |||
+ | /** | ||
+ | * ユーザコントローラの生成 | ||
+ | */ | ||
+ | public function __construct() | ||
+ | { | ||
+ | // モデル | ||
+ | $this-> | ||
+ | |||
+ | // トランザクションアクション登録 | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | * transactional()を使って3つのアクション( '' | ||
\\ | \\ | ||