Ground Sunlight

Windowsで作る - Webプログラミングの開発環境(PHP)

ユーザ用ツール

サイト用ツール


apricot:usage:ja:model

差分

この文書の現在のバージョンと選択したバージョンの差分を表示します。

この比較画面にリンクする

次のリビジョン
前のリビジョン
apricot:usage:ja:model [2020/07/29 13:27]
tanaka 作成
apricot:usage:ja:model [2020/08/12 10:08] (現在)
y2sunlight
ライン 6: ライン 6:
  --- //​[[http://​www.y2sunlight.com|y2sunlight]] 2020-07-29//​  --- //​[[http://​www.y2sunlight.com|y2sunlight]] 2020-07-29//​
  
-[[apricot:​usage:​ja|Apricotの使用法 ​に戻る]]+[[apricot:​usage:​ja|Apricot ​ドキュメント ​に戻る]]
  
 目次 目次
  
 +  * [[apricot:​usage:​ja:​features|Apricot 特徴と概要]]
   * [[apricot:​usage:​ja:​config|Apricot 配置と構成]]   * [[apricot:​usage:​ja:​config|Apricot 配置と構成]]
 +  * [[apricot:​usage:​ja:​errors-logging|Apricot ログとエラー処理]]
   * [[apricot:​usage:​ja:​http|Apricot リクエストとレスポンス]]   * [[apricot:​usage:​ja:​http|Apricot リクエストとレスポンス]]
   * [[apricot:​usage:​ja:​frontend|Apricot フロントエンド]]   * [[apricot:​usage:​ja:​frontend|Apricot フロントエンド]]
ライン 16: ライン 18:
   * [[apricot:​usage:​ja:​middleware|Apricot ミドルウェア]]   * [[apricot:​usage:​ja:​middleware|Apricot ミドルウェア]]
   * [[apricot:​usage:​ja:​controller|Apricot コントローラ]]   * [[apricot:​usage:​ja:​controller|Apricot コントローラ]]
-  * [[apricot:​usage:​ja:​errors-logging|Apricot ログとエラー処理]] 
   * [[apricot:​usage:​ja:​utility|Apricot ユーティリティ]]   * [[apricot:​usage:​ja:​utility|Apricot ユーティリティ]]
  
 ---- ----
  
-===== データベースの利用 ​===== +===== ORMの設定 ===== 
->TODO+ 
 +ORマッパーには[[basic-library:​idiorm:​1.5|Idiorm]]を使用します。Idiormは元々シングルトンとして実装してあるのでそのまま使えます。使い方やメソッドについてはIdiormの[[https://​idiorm.readthedocs.io/​en/​latest/​|マニュアル]]を参照して下さい。 
 + 
 +==== 設定ファイル ==== 
 + 
 +{{fa>​folder-open-o}} ** /​apricot/​config/​setting ** 
 +<code php idiorm.setting.php>​ 
 +<?php 
 +/** 
 + * This file contains Idiorm settings. 
 + */ 
 +return 
 +
 +    '​sqlite'​ => [ 
 +        '​db_file'​ => var_dir('​db/​apricot.sqlite'​),​ 
 +        '​connection_string'​ => '​sqlite:'​.var_dir('​db/​apricot.sqlite'​),​ 
 +        '​caching'​ => true, 
 +        '​logging'​ => true, 
 +    ], 
 +    '​initial_data'​ => [ 
 +        '​user'​=>​ [ 
 +            '​exec'​ =>[ 
 +                '​delete from sqlite_sequence where name=\'​user\'',​ 
 +            ], 
 +            '​rows'​ => [ 
 +                [ 
 +                    '​account'​ =>'​root',​ 
 +                    '​password'​ =>​password_hash('',​ PASSWORD_DEFAULT),​ 
 +                    '​email'​ =>'​root@sample.com',​ 
 +                    '​note'​ =>'​Initial User',​ 
 +                ], 
 +            ], 
 +        ], 
 +    ], 
 +]; 
 +</​code>​ 
 + 
 +  * sqlite : 接続設定(apricotではSQLiteを使用します) 
 +    * sqlite.db_file --- データベースファイルパス (既定値は var/​db/​apricot.sqlite'​) 
 +    * sqlite.connection_string --- 接続文字列 
 +    * sqlite.caching --- キャッシングの有無 
 +    * sqlite.logging --- ロギングの有無 
 + 
 +  * initial_data : 初期データ (テーブルが空の時に自動設定されます) 
 +    * {テーブル名} --- ここではユーザテーブル( user )を指定しています 
 +      * exec --- 実行したいSQLを記述します(複数指定可) 
 +      * rows --- 行データを設定します(複数指定可) 
 + 
 +接続設定の詳細は以下を参照して下さい:\\  
 +https://​idiorm.readthedocs.io/​en/​latest/​configuration.html#​id1 
 + 
 +\\ 
 + 
 +==== 初期設定ファイル ​==== 
 + 
 +データベースの設定は初期設定ファイルで行います。 
 + 
 +{{fa>folder-open-o}} ** /​apricot/​config/​setup ** 
 +<code php idiorm.setup.php>​ 
 +<?php 
 +/** 
 + * Initial setting of ORM (idirom) 
 + */ 
 +return function():​bool 
 +
 +    // Prepares the database files 
 +    $db_file = config('​idiorm.sqlite.db_file'​);​ 
 +    if (!file_exists($db_path=dirname($db_file))) 
 +    { 
 +        @mkdir($db_path,​ null, true); 
 +    } 
 + 
 +    // Checks if DB file exists 
 +    $new_db_file = !file_exists($db_file);​ 
 + 
 +    // Connects to database 
 +    ORM::​configure([ 
 +        '​connection_string'​ => config('​idiorm.sqlite.connection_string'​),​ 
 +        '​caching'​ => config('​idiorm.sqlite.caching',​false),​ 
 +        '​logging'​ => false, 
 +        '​logger'​ => function($log_string,​ $query_time) 
 +        { 
 +            // SQL debug logging 
 +            Apricot\Log::​info("​SQL",​[$log_string]);​ 
 +        }, 
 +    ]); 
 + 
 +    //​------------------------------------------- 
 +    // Creates tables when creating a new DB 
 +    //​------------------------------------------- 
 +    if ($new_db_file) 
 +    { 
 +        $sql_text = file_get_sql(assets_dir('​sql/​create.sql'​));​ 
 +        if (!empty($sql_text)) 
 +        { 
 +            foreach($sql_text as $sql) 
 +            { 
 +                ORM::​get_db()->​exec($sql);​ 
 +            } 
 +        } 
 +    } 
 + 
 +    //​------------------------------------------- 
 +    // Creates initial data when a table is empty 
 +    //​------------------------------------------- 
 +    $initial_data = config('​idiorm.initial_data'​);​ 
 +    if (isset($initial_data)) 
 +    { 
 +        foreach($initial_data as $key=>​$item) 
 +        { 
 +            if(ORM::​for_table($key)->​find_one()===false) 
 +            { 
 +                // SQL execution 
 +                if (array_key_exists('​exec',​ $item)) 
 +                { 
 +                    $exec = (array)$item['​exec'​];​ 
 +                    foreach($exec as $sql) 
 +                    { 
 +                        ORM::​get_db()->​exec($sql);​ 
 +                    } 
 +                } 
 + 
 +                // Creates new records 
 +                if (array_key_exists('​rows',​ $item)) 
 +                { 
 +                    $rows = (array)$item['​rows'​];​ 
 +                    foreach($rows as $row) 
 +                    { 
 +                        $row = ORM::​for_table($key)->​create($row);​ 
 +                        $row->​set_expr('​created_at',​ "​datetime('​now'​)"​);​ 
 +                        $row->​set_expr('​updated_at',​ "​datetime('​now'​)"​);​ 
 +                        $row->​save();​ 
 +                    } 
 +                } 
 +            } 
 +        } 
 +    } 
 + 
 +    // Starts SQL log 
 +    ORM::​configure('​logging'​ , config('​idiorm.sqlite.logging',​false));​ 
 +    return true; // Must return true on success 
 +}; 
 +</​code>​ 
 + 
 +初期設定ファイルでは以下の事をおこないます: 
 + 
 +  * データベースの保存フォルダが存在しない場合は作成します 
 +  * データベースへの接続 
 +  * テーブルの作成 (新しくDBを作った時) 
 +  * 初期ユーザの作成 (ユーザテーブルが空の時) 
 +  * SQLログの開始 (logging設定がtrueの場合) 
 + 
 +\\ 
 + 
 + 
 +===== データベースの構築 ===== 
 + 
 +Apricotでは以下のユーザテーブルを持っています。 
 + 
 +テーブル名 : **user** 
 +^カラム名^型^主Key^属性^説明^ 
 +|id|integer|●|autoincrement|ID| 
 +|account|text| |unique not null|アカウント| 
 +|password|text| |not null|パスワード| 
 +|email|text| |not null|Eメールアドレス| 
 +|note|text| | |備考| 
 +|remember_token|text| | |自動ログイン用| 
 +|created_at|text| |not null|作成日| 
 +|updated_at|text| |not null|更新日| 
 +|version_no|integer| |default 0 not null|バージョンNo| 
 + 
 +  * ユーザ認証は(account,​password)で行います 
 +  * remember_tokenは自動ログイン用の認証トークンです 
 +  * version_noは楽観的ロックで使用します
  
 \\ \\
  
 ===== モデル ===== ===== モデル =====
->TODO+ 
 +ORマッパーが使えるようになったので、モデルのベースクラス( Model )を作ります。Modelクラスは必ず継承して使い、以下のメソッドを持ちます。詳しくはソースコードを参照して下さい。 
 + 
 +^メソッド名^機能^ 
 +|tableName()\\ :​string|テーブル名の取得\\ テーブル名(snake_case)はクラス名(UpperCamelCase)から自動判定します。| 
 +|for_table()\\ :​ORM|ORMオブジェクトの取得| 
 +|findAll()\\ :​array|全件検索\\ ORMの配列を返します。| 
 +|findOne\\ (int $id):​mixed|主キー検索\\ 見つかった場合は ORM を、それ以外は false を返します。| 
 +|create\\ (array $inputs=null):​ORM|モデルの新規作成| 
 +|insert\\ (array $inputs):​ORM|レコードの挿入| 
 +|update\\ ($id, array $inputs):​ORM|レコードの更新\\ レコードが存在しない時、ApplicationExceptionが発生します。\\ 楽観的ロック例外を検知した時、OptimissticLockExceptionが発生します。| 
 +|delete\\ ($id):​ORM|レコードの削除\\ レコードが存在しない時、ApplicationExceptionが発生します。| 
 +|isSuccess()\\ :​bool|最新の更新結果を取得します(insert/​update/​delete)|
  
 \\ \\
  
-===== サービスプロバイー ===== +===== サービスプロバイー ===== 
->TODO+ 
 +サービスコンテナを使用することで、サービスとサービス間の依存関係を登録しておいて後で取得することができます。例えば、サービス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 Apricot\Foundation\Singleton;​
 +use App\Provider;​
 +
 +/**
 + * Container class for service
 + *
 + * @method static Container getInstance() Gets the Container instance.
 + * @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>​
 +<?php
 +namespace App\Controllers;​
 +
 +use App\Foundation\Container;​
 +use App\Foundation\Controller;​
 +
 +/**
 + * Stub Controller
 + */
 +class StubController extends Controller
 +{
 +    /**
 +     * Index Page for this controller.
 +     *
 +     * @return \Apricot\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/usage/ja/model.1595996850.txt.gz · 最終更新: 2020/07/29 13:27 by tanaka