このページの2つのバージョン間の差分を表示します。
| 次のリビジョン | 前のリビジョン | ||
|
apricot:usage:ja:model [2020/07/29 13:27] tanaka 作成 |
apricot:usage:ja:model [2020/09/03 13:45] (現在) 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: | ||
| ---- | ---- | ||
| - | ===== データベースの利用 ===== | + | モデルはデータベース上のテーブルと1対1に対応したクラスで、データベースからデータを取得または設定するためのメソッドを持っています。モデルのベースクラスは[[https:// |
| - | >TODO | + | |
| + | Apricotは比較的小規模なアプリケーション開発をターゲットにしているので、コントローラとモデルによってアプリケーションの作成が可能であると仮定しています。しかしながら、2つ以上のモデルを操作するような少し複雑なトランザクションが必要な場合は、それをサービスとして実装する必要があるかもしれません。現状のApricotではサービスの実装はアプリケーションの問題であるとする立場でなので、本章では、サービスの実装に関する若干のヒントを示すにだけに留めます。 | ||
| \\ | \\ | ||
| - | ===== モデル | + | ===== Modelクラス |
| - | >TODO | + | |
| + | モデルのベースクラスは、'' | ||
| + | |||
| + | <code> | ||
| + | / | ||
| + | </ | ||
| + | |||
| + | ModelクラスはほとんどのことをIdiormのORMクラスに頼っていますが、アプリケーションの共通的な処理を追加しています。Apricotのスケルトンでは、アプリケーションが使用する全てのテーブルで created_at、updated_at、version_no の3つカラムが存在します。 | ||
| + | |||
| + | * 新しくレコードが挿入される時、'' | ||
| + | * レコードが変更される時、'' | ||
| + | * '' | ||
| + | |||
| + | これらの共通処理はアプリケーションに依存するところが大きく、必要に応じて、Modelクラスを変更して下さい。 | ||
| \\ | \\ | ||
| - | ===== サービスプロバイダー ===== | + | ==== 命名規則 |
| - | >TODO | + | |
| + | クラス名とテーブル名の間の名前には以下の例のような命名規則があります。クラス名は Upper Camel (いわゆるPascalケース)、テーブル名はSnakeケースです。 | ||
| + | |||
| + | ^クラス名^テーブル名^ | ||
| + | |User|user| | ||
| + | |UserFriend|user_friend| | ||
| + | |||
| + | クラスのフィールド名とテーブルのカラム名は同じです。両者に命名規則はありません。 | ||
| \\ | \\ | ||
| + | ==== Modelのメソッド ==== | ||
| + | |||
| + | Modeクラスは以下のメソッドを持ちます。 | ||
| + | |||
| + | ^メソッド^機能^ | ||
| + | |tableName(): | ||
| + | |for_table(): | ||
| + | |findAll(): | ||
| + | |findOne(int $id): | ||
| + | |create(array $inputs=null): | ||
| + | |insert(array $inputs): | ||
| + | |update($id, | ||
| + | |delete($id): | ||
| + | |isSuccessful(): | ||
| + | |||
| + | === tableName() === | ||
| + | |||
| + | tableName() は命名規則に従ってクラス名からテーブル名をを取得するメソッドです。 | ||
| + | |||
| + | <code php> | ||
| + | $user = new User(); | ||
| + | $name = $user-> | ||
| + | </ | ||
| + | |||
| + | === forTable() === | ||
| + | |||
| + | ORMのforTable()をラップしたメソッドで、ORMオブジェクトを取得します。 | ||
| + | |||
| + | <code php> | ||
| + | $orm = $user-> | ||
| + | </ | ||
| + | |||
| + | === findAll() === | ||
| + | |||
| + | モデルの対象となるテーブルから全件を検索するメソッドです。このメソッドはORMの配列を返します。 | ||
| + | |||
| + | <code php> | ||
| + | $users = $user-> | ||
| + | foreach($users as $user) | ||
| + | { | ||
| + | $account = $user-> | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === findOne() === | ||
| + | |||
| + | モデルの対象となるテーブルから主キーによる検索を行うメソッドです。見つかった場合は ORM を、それ以外は false を返します。 | ||
| + | |||
| + | <code php> | ||
| + | $user = $user-> | ||
| + | if ($user !== false) | ||
| + | { | ||
| + | // Failure | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | $account = $user-> | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === create() === | ||
| + | |||
| + | 新しいORMオブジェクトを返します。 | ||
| + | |||
| + | <code php> | ||
| + | $new_user = $user-> | ||
| + | </ | ||
| + | |||
| + | 上の例では、新しいORMオブジェクトにはモデルのフィールドはありません。モデルに初期値を設定するには以下のようにします。 | ||
| + | |||
| + | <code php> | ||
| + | $new_user = $user-> | ||
| + | </ | ||
| + | |||
| + | === insert() === | ||
| + | |||
| + | 指定されたモデルデータをテーブルに挿入します。このメソッドはORMオブジェクトを返します。 | ||
| + | |||
| + | <code php> | ||
| + | $inputs = Input:: | ||
| + | |||
| + | $user = $user-> | ||
| + | $new_id = $user-> | ||
| + | </ | ||
| + | |||
| + | === update() === | ||
| + | |||
| + | 指定されたモデルデータでテーブルを更新します。このメソッドはORMオブジェクトを返します。レコードが存在しない時、'' | ||
| + | |||
| + | <code php> | ||
| + | $inputs = Input:: | ||
| + | |||
| + | try | ||
| + | { | ||
| + | $user-> | ||
| + | } | ||
| + | catch(ApplicationException $e) | ||
| + | { | ||
| + | // OptimissticLockException is also an ApplicationException. | ||
| + | // Do something. | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === delete() === | ||
| + | |||
| + | 指定された主キーのレコードをテーブルから削除します。このメソッドはORMオブジェクトを返します。レコードが存在しない時、ApplicationExceptionをスローします。 | ||
| + | |||
| + | <code php> | ||
| + | try | ||
| + | { | ||
| + | $user-> | ||
| + | } | ||
| + | catch(ApplicationException $e) | ||
| + | { | ||
| + | // Do something. | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === isSuccessful() === | ||
| + | |||
| + | 最新の更新結果をブーリアンで返します。対象は insert()、update()、delete()の各メソッドです。 | ||
| + | |||
| + | <code php> | ||
| + | $successful = $user-> | ||
| + | </ | ||
| + | |||
| + | \\ | ||
| + | |||
| + | ===== Modelの継承 ===== | ||
| + | |||
| + | 以下はもっとも簡単なModelの継承の例です。Modelを継承するだけで、Modelクラスのメソッドが利用でき、簡単なモデルなら直ぐにアクションの実装に取り掛かれます。 | ||
| + | |||
| + | {{fa> | ||
| + | <code php User.php> | ||
| + | <?php | ||
| + | namespace App\Models; | ||
| + | use App\Foundation\Model; | ||
| + | |||
| + | /** | ||
| + | * User Model | ||
| + | */ | ||
| + | class User extends Model | ||
| + | { | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | 次の例は、Apticotのスケルトンで提供されているユーザモデルです。この例では、insert()とupdate()をオーバーロードして個別の処理を追加しています。 | ||
| + | |||
| + | <code php User.php> | ||
| + | <?php | ||
| + | namespace App\Models; | ||
| + | use App\Foundation\Model; | ||
| + | use ORM; | ||
| + | |||
| + | /** | ||
| + | * User Model | ||
| + | */ | ||
| + | class User extends Model | ||
| + | { | ||
| + | /** | ||
| + | * {@inheritDoc} | ||
| + | * @see \App\Foundation\Model:: | ||
| + | */ | ||
| + | public function insert(array $inputs): | ||
| + | { | ||
| + | // Encrypt the password that is required for new registration. | ||
| + | $inputs[' | ||
| + | |||
| + | return parent:: | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * {@inheritDoc} | ||
| + | * @see \App\Foundation\Model:: | ||
| + | */ | ||
| + | public function update($id, array $inputs): | ||
| + | { | ||
| + | // Updates a password only if entered | ||
| + | if(empty($inputs[' | ||
| + | |||
| + | if(array_key_exists(' | ||
| + | { | ||
| + | // Encrypts the entered password | ||
| + | $inputs[' | ||
| + | } | ||
| + | |||
| + | return parent:: | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | '' | ||
| + | |||
| + | \\ | ||
| + | |||
| + | ===== サービス ===== | ||
| + | |||
| + | Apricotではサービスの実装に関する具体的で明確な指針を提供してはいませんが、その代わりに1つの例題を提供しています。この例題は、''/ | ||
| + | |||
| + | {{fa> | ||
| + | <code php SampleServices.php> | ||
| + | <?php | ||
| + | namespace App\Services; | ||
| + | |||
| + | /** | ||
| + | * Sample Service | ||
| + | */ | ||
| + | class SampleService | ||
| + | { | ||
| + | /** | ||
| + | * The number of users | ||
| + | * @var int | ||
| + | */ | ||
| + | private $count = 0; | ||
| + | |||
| + | /** | ||
| + | * Creates a sample service. | ||
| + | */ | ||
| + | public function __construct(\App\Models\User $user) | ||
| + | { | ||
| + | $this-> | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * Get the number of users | ||
| + | */ | ||
| + | public function getUserCount() | ||
| + | { | ||
| + | return $this-> | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | サービスの構造は[[apricot: | ||
| + | |||
| + | これらの問題を解決する為に、Apricotのコアが使用している [[https:// | ||
| + | |||
| + | Apricotでは League/ | ||
| + | |||
| + | === Auto Wiring === | ||
| + | |||
| + | Auto Wiring とは、コンストラクター引数の型ヒントを調べることにより、オブジェクトとそのすべての依存関係を再帰的に自動的に解決する機能です。これによってコントローラーにモデルやサービスのコンストラクタインジェクションが実現できます。詳しくは「[[apricot: | ||
| + | |||
| + | === サービスプロバイダー === | ||
| + | |||
| + | サービスプロバイダーを利用して、サービスをシングルトンとしてアプリケーションに登録することができます。詳しくは、「[[apricot: | ||
| + | |||
| + | \\ | ||