Ground Sunlight

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

ユーザ用ツール

サイト用ツール


サイドバー

メインメニュー

道具箱

リポジトリ編

フレームワーク編

Webサービス編

自然言語処理環境編

メタ
リンク


このページへのアクセス
今日: 1 / 昨日: 2
総計: 22

apricot:usage:ja:model
編集中

Apricot データベースとモデル

ORMの設定

ORマッパーにはIdiormを使用します。Idiormは元々シングルトンとして実装してあるのでそのまま使えます。使い方やメソッドについてはIdiormのマニュアルを参照して下さい。

設定ファイル

/apricot/config/setting

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',
                ],
            ],
        ],
    ],
];
  • 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


初期設定ファイル

データベースの設定は初期設定ファイルで行います。

/apricot/config/setup

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
};

初期設定ファイルでは以下の事をおこないます:

  • データベースの保存フォルダが存在しない場合は作成します
  • データベースへの接続
  • テーブルの作成 (新しくDBを作った時)
  • 初期ユーザの作成 (ユーザテーブルが空の時)
  • SQLログの開始 (logging設定がtrueの場合)


データベースの構築

Apricotでは以下のユーザテーブルを持っています。

テーブル名 : user

カラム名主Key属性説明
idintegerautoincrementID
accounttext unique not nullアカウント
passwordtext not nullパスワード
emailtext not nullEメールアドレス
notetext 備考
remember_tokentext 自動ログイン用
created_attext not null作成日
updated_attext not null更新日
version_nointeger default 0 not nullバージョンNo
  • ユーザ認証は(account,password)で行います
  • remember_tokenは自動ログイン用の認証トークンです
  • version_noは楽観的ロックで使用します


モデル

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)


サービスプロバイター

サービスコンテナを使用することで、サービスとサービス間の依存関係を登録しておいて後で取得することができます。例えば、サービスAがモデルBとモデルCを使用しているような場合、サービスコンテナにサービスAを要求すると、自動的にモデルBとCを生成し、それらをサービスAのコンストラクタに与えてサービスAを生成してくれます。

サービスプロバイターは、アプリケーション内の全てのサービスコンテナを登録し整理する方法を提供してくれます。また、サービスプロバイダーではサービスが取得された時点で遅延登録されるため、アプリケーションのパフォーマンス向上にも寄与します。

League/Container でサービスプロバイダーを構築するには以下のステップに従います。

  1. League/Container の 基本サービスプロバイダークラス( AbstractServiceProvider )を拡張して 独自のサービスプロバイダーを作ります。
  2. League/Container の Container クラスに 独自のサービスプロバイダーを登録します。

Apricotでは、独自のサービスプロバイダーとして App\Provider クラスを定義し、それを登録する App\Foundation\Container クラスをシングルトンとして実装します。サービスの使用者は、App\Foundation\Containerが持っている PSR-11 に準じた get()has() を使ってサービスを利用することができます。


Providerクラス

以下に、League/Container の 基本サービスプロバイダークラス( AbstractServiceProvider )を拡張したApricot独自のサービスプロバイダークラス( Provider )を以下に示します。

/apricot/app

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 );
     }
}

このクラスは、名前空間Appの直下に存在し、アプリケーションのモデル及びサービスのマップを提供します。現版のApricotでは、モデルはユーザモデル( User )だけで、サービスについては存在しません。モデルやサービスを追加する場合は、上例に習って適宜追加して下さい。

現版のApricotでは、サービスは存在しませんが、サービス用として以下のフォルダが予約されています。

/apricot/app/Services

尚、League/Container のサービスプロバイダーについての詳細はこちらをご覧ください。


App\Foundation\Containerクラス

App\Foundation\Containerクラスは、\League\Container\Container クラスを生成し、Apricotのサービスプロバイダー(Provider)を登録したクラスで、シングルトンとして動作します。

使用法: Container::{メソッド}

メソッド機能
mixed get(string $id)識別子idでコンテナのエントリを検索して返します。
bool has(string $id)コンテナが指定された識別子idのエントリを返すことができる場合はtrueを返します。

/apricot/app/Foundation

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;
    }
}


サービスコンテナの使用例

スタブコントローラ

サービスコンテナをテストするために、スタブコントローラを以下のように修正します。

/apricot/app/Controllers

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]);
    }
}
  • Container::get('user') でユーザモデルを生成します。
  • ユーザモデルの findAll() を実行して全ユーザのリストを取得します。
  • ユーザ数を表示するために、テンプレート変数 $messages をセットします。


コメント

コメントを入力. Wiki文法が有効です:
 
apricot/usage/ja/model.txt · 最終更新: 2020/08/12 10:08 by y2sunlight