データベース抽象化レイヤー

Phalcon\Db is the component behind Phalcon\Mvc\Model that powers the model layer in the framework. これは、C言語で完全に書かれたデータベースシステムのための独立した高レベルの抽象化レイヤーで構成されています。

このコンポーネントは従来のモデルを使用するよりも、データベースを低レベルで操作することができます。

データベースアダプター

This component makes use of adapters to encapsulate specific database system details. Phalcon uses PDO to connect to databases. The following database engines are supported:

クラス 説明
Phalcon\Db\Adapter\Pdo\Mysql 世界で最も使用されているリレーショナルデータベース管理システム (RDBMS) です。サーバーで動作し、多数のユーザーがいくつかのデータベースにアクセスできます。
Phalcon\Db\Adapter\Pdo\Postgresql PostgreSQL は、強力なオープンソースのリレーショナルデータベースシステムです。 これは15年以上の積極的な開発と実績のあるアーキテクチャを備えており、信頼性、データの完全性、正確性について高い評価を得ています。
Phalcon\Db\Adapter\Pdo\Sqlite SQLiteは、自己完結型でサーバレスでゼロ設定のトランザクション型SQLデータベースエンジンを実装したソフトウェアライブラリです

ファクトリー

Loads PDO Adapter class using adapter option. For example:

<?php

use Phalcon\Db\Adapter\Pdo\Factory;

$options = [
    'host'     => 'localhost',
    'dbname'   => 'blog',
    'port'     => 3306,
    'username' => 'sigma',
    'password' => 'secret',
    'adapter'  => 'mysql',
];

$db = Factory::load($options);

独自のアダプターを実装

The Phalcon\Db\AdapterInterface interface must be implemented in order to create your own database adapters or extend the existing ones.

データベースの方言

Phalcon encapsulates the specific details of each database engine in dialects. Those provide common functions and SQL generator to the adapters.

クラス 説明
Phalcon\Db\Dialect\Mysql MySQL データベースシステム向けのSQL方言
Phalcon\Db\Dialect\Postgresql PostgreSQLデータベースシステム向けのSQL方言
Phalcon\Db\Dialect\Sqlite SQLiteデータベースシステム向けのSQL方言

独自の方言を実装します

The Phalcon\Db\DialectInterface interface must be implemented in order to create your own database dialects or extend the existing ones. PHQLが理解するより多くのコマンドやメソッドを追加して、現在の方言を強化できます。

For instance when using the MySQL adapter, you might want to allow PHQL to recognize the MATCH ... AGAINST ... syntax. We associate that syntax with MATCH_AGAINST

方言をインスタンス化します。 カスタム関数を追加して、PHQLが、パースプロセス中にこれを検出したときに、理解できるようにします。 次の例では、MATCH_AGAINST と呼ばれる新しいカスタム関数を登録します。 その後、カスタマイズされた方言オブジェクトをDBコネクションに追加するだけです。

<?php

use Phalcon\Db\Dialect\MySQL as SqlDialect;
use Phalcon\Db\Adapter\Pdo\MySQL as Connection;

$dialect = new SqlDialect();

$dialect->registerCustomFunction(
    'MATCH_AGAINST',
    function($dialect, $expression) {
        $arguments = $expression['arguments'];
        return sprintf(
            " MATCH (%s) AGAINST (%)",
            $dialect->getSqlExpression($arguments[0]),
            $dialect->getSqlExpression($arguments[1])
         );
    }
);

$connection = new Connection(
    [
        "host"          => "localhost",
        "username"      => "root",
        "password"      => "",
        "dbname"        => "test",
        "dialectClass"  => $dialect
    ]
);

PHQLでこの新しい関数を使用できます。この場合、これは適切なSQL構文に翻訳されます:

$phql = "
  SELECT *
  FROM   Posts
  WHERE  MATCH_AGAINST(title, :pattern:)";

$posts = $modelsManager->executeQuery($phql, ['pattern' => $pattern]);

データベースへの接続

接続を作成するためには、アダプター クラスをインスタンス化する必要があります。 接続パラメーターの配列だけが必要です。 次の例は、必須またはオプションのパラメーターを渡す接続を作成する方法を示しています。

MySQL 必須要素
<?php

$config = [
    'host'     => '127.0.0.1',
    'username' => 'mike',
    'password' => 'sigma',
    'dbname'   => 'test_db',
];
MySQL オプション
$config['persistent'] = false;
MySQLの接続を作成
$connection = new \Phalcon\Db\Adapter\Pdo\Mysql($config);
PostgreSQL 必須要素
<?php

$config = [
    'host'     => 'localhost',
    'username' => 'postgres',
    'password' => 'secret1',
    'dbname'   => 'template',
];
PostgreSQL オプション
$config['schema'] = 'public';
PostgreSQLの接続を作成
$connection = new \Phalcon\Db\Adapter\Pdo\Postgresql($config);
SQLite 必須要素
<?php

$config = [
    'dbname' => '/path/to/database.db',
];
SQLite接続を作成
$connection = new \Phalcon\Db\Adapter\Pdo\Sqlite($config);

PDO の追加オプションを設定

optionsパラメータを渡すことで接続時にPDOオプションを設定できます:

<?php

$connection = new \Phalcon\Db\Adapter\Pdo\Mysql(
    [
        'host'     => 'localhost',
        'username' => 'root',
        'password' => 'sigma',
        'dbname'   => 'test_db',
        'options'  => [
            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'",
            PDO::ATTR_CASE               => PDO::CASE_LOWER,
        ]
    ]
);

Factoryを使用した接続

単純にini ファイルを使ってあなたの データベースサービスをデータベースに設定/接続できます。

[database]
host = TEST_DB_MYSQL_HOST
username = TEST_DB_MYSQL_USER
password = TEST_DB_MYSQL_PASSWD
dbname = TEST_DB_MYSQL_NAME
port = TEST_DB_MYSQL_PORT
charset = TEST_DB_MYSQL_CHARSET
adapter = mysql
<?php

use Phalcon\Config\Adapter\Ini;
use Phalcon\Di;
use Phalcon\Db\Adapter\Pdo\Factory;

$di = new Di();
$config = new Ini('config.ini');

$di->set('config', $config);

$di->set(
    'db', 
    function () {
        return Factory::load($this->config->database);
    }
);

上記は適切なデータベース インスタンスを返ます。また、アプリケーションのコードを1 行も変更することがなく、接続資格情報を変更したり、データベース アダプターを変更したりできる利点があります。

行の検索

Phalcon\Db provides several methods to query rows from tables. The specific SQL syntax of the target database engine is required in this case:

<?php

$sql = 'SELECT id, name FROM robots ORDER BY name';

// データベースシステムへSQLステートメントを送信
$result = $connection->query($sql);

// 各robotの名前を表示
while ($robot = $result->fetch()) {
   echo $robot['name'];
}

// 配列内のすべての行を取得する
$robots = $connection->fetchAll($sql);
foreach ($robots as $robot) {
   echo $robot['name'];
}

// 最初の行だけを取得する
$robot = $connection->fetchOne($sql);

デフォルトで、これらの呼び出しは連想配列と数値インデックスを持つ配列を両方とも作成します。 Phalcon\Db\Result::setFetchMode() を使用してこの動作を変更できます。 このメソッドは、どの種類のインデックスの種類が必要なのかを定義する、定数を受け取ります。

定数 説明
Phalcon\Db::FETCH_NUM 数字インデックスのある配列を返す
Phalcon\Db::FETCH_ASSOC 関連インデックスのある配列を返す
Phalcon\Db::FETCH_BOTH 関連インデックスと数字インデックスのある配列を返す
Phalcon\Db::FETCH_OBJ 配列ではなく、オブジェクトを返す。
<?php

$sql = 'SELECT id, name FROM robots ORDER BY name';
$result = $connection->query($sql);

$result->setFetchMode(Phalcon\Db::FETCH_NUM);
while ($robot = $result->fetch()) {
   echo $robot[0];
}

The Phalcon\Db::query() returns an instance of Phalcon\Db\Result\Pdo. これらのオブジェクトは、返された resultset に関連した機能(トラバース、特定のレコードのシーク、カウント)をカプセル化します。

<?php

$sql = 'SELECT id, name FROM robots';
$result = $connection->query($sql);

// resultset のトラバース
while ($robot = $result->fetch()) {
   echo $robot['name'];
}

// 3番目の row のシーク
$result->seek(2);
$robot = $result->fetch();

// resultset のカウント
echo $result->numRows();

パラメーターのバインド

Bound parameters is also supported in Phalcon\Db. バインドされたパラメータを使用することで、パフォーマンスの影響は最小限に抑えられますが、コードがSQLインジェクション攻撃の対象になる可能性を排除するために、この方法を使用することをお勧めします。 文字列と位置指定のプレースホルダーの両方をサポートしています。 パラメータのバインドは、以下のように簡単に実施できます:

<?php

// 数値プレースホルダーにバインド
$sql    = 'SELECT * FROM robots WHERE name = ? ORDER BY name';
$result = $connection->query(
    $sql,
    [
        'Wall-E',
    ]
);

// 名前つきプレースホルダーにバインド
$sql     = 'INSERT INTO `robots`(name`, year) VALUES (:name, :year)';
$success = $connection->query(
    $sql,
    [
        'name' => 'Astro Boy',
        'year' => 1952,
    ]
);

数値プレースホルダを使用する場合は、整数を1または2として定義する必要があります。 この場合、 ‘1’または ‘2’は文字列であり数字ではないため、プレースホルダを正常に置き換えることができません。 アダプターのデータはすべてPDO Quoteを使って自動的にエスケープ処理されます。

この関数は接続文字セットを考慮しているため、接続パラメータまたはデータベースサーバー設定で正しい文字セットを定義することをお勧めします。データセットを格納または取得するときに間違った文字セットが望ましくない影響を及ぼすためです。

Also, you can pass your parameters directly to the execute or query methods. In this case bound parameters are directly passed to PDO:

<?php

// Binding with PDO placeholders
$sql    = 'SELECT * FROM robots WHERE name = ? ORDER BY name';
$result = $connection->query(
    $sql,
    [
        1 => 'Wall-E',
    ]
);

型指定されたプレース ホルダー

プレースホルダーは、SQL インジェクション攻撃を避けるためにパラメーターをバインドすることができます:

<?php

$phql = "SELECT * FROM Store\Robots WHERE id > :id:";

$robots = $this->modelsManager->executeQuery($phql, ['id' => 100]);

しかし、いくつかのデータベースでは、バインドパラメータが特定のタイプのプレースホルダーを使用する時、追加のアクションが必要になります:

<?php

use Phalcon\Db\Column;

// ...

$phql = "SELECT * FROM Store\Robots LIMIT :number:";
$robots = $this->modelsManager->executeQuery(
    $phql,
    ['number' => 10],
    Column::BIND_PARAM_INT
);

executeQuery() でバインドタイプを指定する代わりに、パラメーターで型指定されたプレース ホルダーを使用できます:

<?php

$phql = "SELECT * FROM Store\Robots LIMIT {number:int}";
$robots = $this->modelsManager->executeQuery(
    $phql,
    ['number' => 10]
);

$phql = "SELECT * FROM Store\Robots WHERE name <> {name:str}";
$robots = $this->modelsManager->executeQuery(
    $phql,
    ['name' => $name]
);

タイプを指定する必要がない場合は、型を省略することもできます:

<?php

$phql = "SELECT * FROM Store\Robots WHERE name <> {name}";
$robots = $this->modelsManager->executeQuery(
    $phql,
    ['name' => $name]
);

型指定されたプレースホルダーは非常に有用です。というのも、静的な配列をプレースホルダーとしてバインドできますが、その際に配列の各要素を単独で渡す必要はないからです:

<?php

$phql = "SELECT * FROM Store\Robots WHERE id IN ({ids:array})";
$robots = $this->modelsManager->executeQuery(
    $phql,
    ['ids' => [1, 2, 3, 4]]
);

以下のタイプが使用できます:

バインドタイプ バインドタイプ定数
str Column::BIND_PARAM_STR {name:str}
int Column::BIND_PARAM_INT {number:int}
double Column::BIND_PARAM_DECIMAL {price:double}
bool Column::BIND_PARAM_BOOL {enabled:bool}
blob Column::BIND_PARAM_BLOB {image:blob}
null Column::BIND_PARAM_NULL {exists:null}
array Column::BIND_PARAM_STRの配列 {codes:array}
array-str Column::BIND_PARAM_STRの配列 {names:array-str}
array-int Column::BIND_PARAM_INTの配列 {flags:array-int}

バインドされたパラメータのキャスト

デフォルトでは、バインドされたパラメーターは PHP ユーザーランドで指定されたバインド型にキャストされていません。このオプションで、PDO でそれらをバインドする前に、Phalconが値をキャストできます。 この問題が発生する一般的な状況は、LIMIT/OFFSET プレース ホルダーの文字列を渡す場合です:

<?php

$number = '100';
$robots = $modelsManager->executeQuery(
    'SELECT * FROM Some\Robots LIMIT {number:int}',
    ['number' => $number]
);

これは、次の例外を発生します:

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]:
Syntax error or access violation: 1064 You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right
syntax to use near ''100'' at line 1' in /Users/scott/demo.php:78

This happens because 100 is a string variable. It is easily fixable by casting the value to integer first:

<?php

$number = '100';
$robots = $modelsManager->executeQuery(
    'SELECT * FROM Some\Robots LIMIT {number:int}',
    ['number' => (int) $number]
);

ただしこのソリューションの開発者は、どのようにバインドされているパラメーターが渡されるのか、またそのタイプについての特別な注意を払う必要があります。 このタスクを簡単にし、予期しない例外を回避するために、このキャストを行うように Phalconに指示することができます:

<?php

\Phalcon\Db::setup(['forceCasting' => true]);

バインドタイプによって次のアクションが実行されます:

バインドタイプ アクション
Column::BIND_PARAM_STR 値をネイティブなPHP文字列にキャストします。
Column::BIND_PARAM_INT 値をネイティブなPHP整数にキャストします。
Column::BIND_PARAM_BOOL 値をネイティブなPHP論理型にキャストします。
Column::BIND_PARAM_DECIMAL 値をネイティブなPHP実数型(double) にキャストします。

Hydrateでのキャスト

データベースシステムからの返り値はPDOによって常に文字列型で表現されます。その値が数字型や論理型であっても、文字列型です。 これは、いくつかのカラムの型が、そのサイズ制限により対応する PHP ネイティブ型で表現できないために発生します。 例えば、MySQL の BIGINT は、PHP の 32 ビット整数として表すことができない大きな整数を格納できます。 そのため、PDO とORM は、デフォルトで文字列としてすべての値を残す、安全策を実施します。

ORM が自動的にこれらの型へ対応する PHP ネイティブ型に安全にキャストするように設定できます。

<?php

\Phalcon\Mvc\Model::setup(['castOnHydrate' => true]);

このようにして、厳密に演算子を使用したり、変数のタイプを推測させたりすることができます:

<?php

$robot = Robots::findFirst();
if (11 === $robot->id) {
    echo $robot->name;
}

行の挿入、更新、および削除

行を挿入、更新、または削除するには、生のSQLを使用するか、クラスが提供するプリセット関数を使用します:

<?php

// 生のSQL文を使用したデータの挿入
$sql     = 'INSERT INTO `robots`(`name`, `year`) VALUES ('Astro Boy', 1952)';
$success = $connection->execute($sql);

// プレースホルダー付き
$sql     = 'INSERT INTO `robots`(`name`, `year`) VALUES (?, ?)';
$success = $connection->execute(
    $sql,
    [
        'Astro Boy',
        1952,
    ]
);

// 必要なSQLを動的に生成する
$success = $connection->insert(
    'robots',
    [
        'Astro Boy',
        1952,
    ],
    [
        'name',
        'year',
    ],
);

// 必要なSQLを動的に生成する(別のシンタックス)
$success = $connection->insertAsDict(
    'robots',
    [
        'name' => 'Astro Boy',
        'year' => 1952,
    ]
);

// 生のSQL文によるデータの更新
$sql     = 'UPDATE `robots` SET `name` = 'Astro boy' WHERE `id` = 101';
$success = $connection->execute($sql);

// プレースホルダー付き
$sql     = 'UPDATE `robots` SET `name` = ? WHERE `id` = ?';
$success = $connection->execute(
    $sql,
    [
        'Astro Boy',
        101,
    ]
);

// 必要なSQLを動的に生成する
$success = $connection->update(
    'robots',
    [
        'name',
    ],
    [
        'New Astro Boy',
    ],
    'id = 101' // 注意! この場合、値はエスケープされません
);

// 必要なSQLを動的に生成する(別のシンタックス)
$success = $connection->updateAsDict(
    'robots',
    [
        'name' => 'New Astro Boy',
    ],
    'id = 101' // 注意! この場合、値はエスケープされません
);

// エスケープ条件
$success = $connection->update(
    'robots',
    [
        'name',
    ],
    [
        'New Astro Boy',
    ],
    [
        'conditions' => 'id = ?',
        'bind'       => [101],
        'bindTypes'  => [PDO::PARAM_INT], // オプションのパラメータ
    ]
);
$success = $connection->updateAsDict(
    'robots',
    [
        'name' => 'New Astro Boy',
    ],
    [
        'conditions' => 'id = ?',
        'bind'       => [101],
        'bindTypes'  => [PDO::PARAM_INT], // オプションのパラメータ
    ]
);

// 生のSQL文を使用したデータの削除
$sql     = 'DELETE `robots` WHERE `id` = 101';
$success = $connection->execute($sql);

// プレースホルダー付き
$sql     = 'DELETE `robots` WHERE `id` = ?';
$success = $connection->execute($sql, [101]);

// 必要なSQLを動的に生成する
$success = $connection->delete(
    'robots',
    'id = ?',
    [
        101,
    ]
);

トランザクションとネストしたトランザクション

Working with transactions is supported as it is with PDO. Perform data manipulation inside transactions often increase the performance on most database systems:

<?php

try {
    // トランザクション開始
    $connection->begin();

    // 複数のSQL文を実行
    $connection->execute('DELETE `robots` WHERE `id` = 101');
    $connection->execute('DELETE `robots` WHERE `id` = 102');
    $connection->execute('DELETE `robots` WHERE `id` = 103');

    // 全てうまくいけばコミット
    $connection->commit();
} catch (Exception $e) {
    // 例外が発生したらトランザクションをロールバック
    $connection->rollback();
}

In addition to standard transactions, Phalcon\Db provides built-in support for nested transactions (if the database system used supports them). 二回begin()を呼び出すとき、 入れ子になったトランザクションが作成されます:

<?php

try {
    // トランザクション開始
    $connection->begin();

    // 複数のSQL文を実行
    $connection->execute('DELETE `robots` WHERE `id` = 101');

    try {
        // 入れ子トランザクション開始
        $connection->begin();

        // 入れ子トランザクションのSQL文を実行
        $connection->execute('DELETE `robots` WHERE `id` = 102');
        $connection->execute('DELETE `robots` WHERE `id` = 103');

        // セーブポイントを作成
        $connection->commit();
    } catch (Exception $e) {
        // エラー発生、入れ子トランザクションを解放
        $connection->rollback();
    }

    // 継続、他のSQL文を実行
    $connection->execute('DELETE `robots` WHERE `id` = 104');

    // 全てうまくいけばコミット
    $connection->commit();
} catch (Exception $e) {
    // 例外が発生したらトランザクションをロールバック
    $connection->rollback();
}

データベースのイベント

Phalcon\Db is able to send events to a EventsManager if it’s present. ブール値 false を返すいくつかのイベントは、アクティブな操作を停止することがあります。 以下のイベントがサポートされています。

イベント名 トリガー 処理中断が可能
afterConnect データベースシステムへの接続が成功した後 いいえ
beforeQuery データベースシステムへSQLステートメントを送信する前 はい
afterQuery データベースシステムへSQLステートメントを送信した後 いいえ
beforeDisconnect 一時的なデータベース接続を切断する前 いいえ
beginTransaction トランザクションが実行される前 いいえ
rollbackTransaction トランザクションがロールバックされる前 いいえ
commitTransaction トランザクションがコミットされる前 いいえ

Bind an EventsManager to a connection is simple, Phalcon\Db will trigger the events with the type db:

<?php

use Phalcon\Events\Manager as EventsManager;
use Phalcon\Db\Adapter\Pdo\Mysql as Connection;

$eventsManager = new EventsManager();

// 全てのデータベースのイベントをリッスン
$eventsManager->attach('db', $dbListener);

$connection = new Connection(
    [
        'host'     => 'localhost',
        'username' => 'root',
        'password' => 'secret',
        'dbname'   => 'invo',
    ]
);

// イベントマネージャをそのデータベースアダプタのインスタンスへ割り当て
$connection->setEventsManager($eventsManager);

SQL操作の停止が便利なのは、例えば、あなたが最後のリソースのSQLインジェクションのチェッカーなどを実装しようと思っている場合です:

<?php

use Phalcon\Events\Event;

$eventsManager->attach(
    'db:beforeQuery',
    function (Event $event, $connection) {
        $sql = $connection->getSQLStatement();

        // SQL ステートメントに悪意のあるワードがあるか確認
        if (preg_match('/DROP|ALTER/i', $sql)) {
            // このアプリケーションではDROPやALTER操作は許可されていません。
            // これはSQL インジェクションです!
            return false;
        }

        // OK
        return true;
    }
);

SQL ステートメントのプロファイリング

Phalcon\Db includes a profiling component called Phalcon\Db\Profiler, that is used to analyze the performance of database operations so as to diagnose performance problems and discover bottlenecks.

Database profiling is really easy With Phalcon\Db\Profiler:

<?php

use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Db\Profiler as DbProfiler;

$eventsManager = new EventsManager();

$profiler = new DbProfiler();

// すべてのデータベースイベントをリッスンします。
$eventsManager->attach(
    'db',
    function (Event $event, $connection) use ($profiler) {
        if ($event->getType() === 'beforeQuery') {
            $sql = $connection->getSQLStatement();

            // 接続をしたままプロファイルを開始
            $profiler->startProfile($sql);
        }

        if ($event->getType() === 'afterQuery') {
            // プロファイリングを停止
            $profiler->stopProfile();
        }
    }
);

// イベントマネージャーに接続を割り当て
$connection->setEventsManager($eventsManager);

$sql = 'SELECT buyer_name, quantity, product_name '
     . 'FROM buyers '
     . 'LEFT JOIN products ON buyers.pid = products.id';

// SQLステートメントの実行
$connection->query($sql);

// プロファイラ内の最後のプロファイルを取得
$profile = $profiler->getLastProfile();

echo 'SQL Statement: ', $profile->getSQLStatement(), "\n";
echo 'Start Time: ', $profile->getInitialTime(), "\n";
echo 'Final Time: ', $profile->getFinalTime(), "\n";
echo 'Total Elapsed Time: ', $profile->getTotalElapsedSeconds(), "\n";

You can also create your own profile class based on Phalcon\Db\Profiler to record real time statistics of the statements sent to the database system:

<?php

use Phalcon\Events\Manager as EventsManager;
use Phalcon\Db\Profiler as Profiler;
use Phalcon\Db\Profiler\Item as Item;

class DbProfiler extends Profiler
{
    /**
     * DBサーバーへSQLステートメントを送る前に実行
     */
    public function beforeStartProfile(Item $profile)
    {
        echo $profile->getSQLStatement();
    }

    /**
     * DBサーバーへSQLステートメントを送った後に実行
     */
    public function afterEndProfile(Item $profile)
    {
        echo $profile->getTotalElapsedSeconds();
    }
}

// イベントマネージャの作成
$eventsManager = new EventsManager();

// リスナーの作成
$dbProfiler = new DbProfiler();

// 全データベースイベントをリッスンするリスナーにアタッチ
$eventsManager->attach('db', $dbProfiler);

SQL ステートメントのロギング

Using high-level abstraction components such as Phalcon\Db to access a database, it is difficult to understand which statements are sent to the database system. Phalcon\Logger interacts with Phalcon\Db, providing logging capabilities on the database abstraction layer.

<?php

use Phalcon\Logger;
use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Logger\Adapter\File as FileLogger;

$eventsManager = new EventsManager();

$logger = new FileLogger('app/logs/db.log');

$eventsManager->attach(
    'db:beforeQuery',
    function (Event $event, $connection) use ($logger) {
        $sql = $connection->getSQLStatement();

        $logger->log($sql, Logger::INFO);
    }
);

// eventsManagerをdbアダプタインスタンスに割り当てる
$connection->setEventsManager($eventsManager);

// 複数のSQL文を実行
$connection->insert(
    'products',
    [
        'Hot pepper',
        3.50,
    ],
    [
        'name',
        'price',
    ]
);

上記のように、ファイルapp/logs/db.logには次のようなものが含まれます:

[Sun, 29 Apr 12 22:35:26 -0500][DEBUG][Resource Id #77] INSERT INTO products
(name, price) VALUES ('Hot pepper', 3.50)

独自のロガーを実装

データベースのクエリのため、独自のロガー クラスを実装できます。それはlog と呼ぶ単一のメソッドを実装するクラスを作成することによって行います。 このメソッドは、最初の引数として string を受け入れる必要があります。 ログ オブジェクトをPhalcon\Db::setLogger()に渡して、その時から実行されたすべての SQL ステートメントの結果を記録するメソッドを呼び出せます。

テーブル/ビューの定義取得

Phalcon\Db also provides methods to retrieve detailed information about tables and views:

<?php

// test_db データベースのテーブルを取得
$tables = $connection->listViews('test_db');

// このデータベースに 'robots' テーブルがあるかどうか
$exists = $connection->tableExists('robots');

// 'robots'フィールドから、名前、データタイプ、特別な機能を取得
$fields = $connection->describeColumns('robots');
foreach ($fields as $field) {
    echo 'Column Type: ', $field['Type'];
}

// 'robots'テーブルのインデックスを取得
$indexes = $connection->describeIndexes('robots');
foreach ($indexes as $index) {
    print_r(
        $index->getColumns()
    );
}

// 'robots'テーブルの外部キーを取得
$references = $connection->describeReferences('robots');
foreach ($references as $reference) {
    // 参照カラムの表示
    print_r(
        $reference->getReferencedColumns()
    );
}

テーブルの説明は MySQLの DESCRIBEコマンドとほとんど同じで、次の情報が含まれています。

フィールド タイプ キー Null
フィールド名 カラムタイプ プライマリーキーまたはインデックスのカラムかどうか カラムがnullを許可するかどうか

ビューに関する情報を取得するメソッドは、サポートされているすべてのデータベースシステムに対しても実装されています:

<?php

// Get views on the test_db database
$tables = $connection->listViews('test_db');

// Is there a view 'robots' in the database?
$exists = $connection->viewExists('robots');

テーブルの作成/変更/削除

(MySQL、Postgresql など) データベースシステム は、CREATEALTER または DROP などのコマンドを使ってテーブルを作成、変更、削除する機能を提供します。 SQL のシンタックスは、どのデータベースシステムを使用しているかによって異なります。 Phalcon\Db は、テーブルを変更する統一されたインターフェイスを提供しています。ターゲットのストレージシステムに基づいたSQL シンタックスの違いを必要としません。

テーブルの作成

テーブルを作成する方法を示します。

<?php

use \Phalcon\Db\Column as Column;

$connection->createTable(
    'robots',
    null,
    [
       'columns' => [
            new Column(
                'id',
                [
                    'type'          => Column::TYPE_INTEGER,
                    'size'          => 10,
                    'notNull'       => true,
                    'autoIncrement' => true,
                    'primary'       => true,
                ]
            ),
            new Column(
                'name',
                [
                    'type'    => Column::TYPE_VARCHAR,
                    'size'    => 70,
                    'notNull' => true,
                ]
            ),
            new Column(
                'year',
                [
                    'type'    => Column::TYPE_INTEGER,
                    'size'    => 11,
                    'notNull' => true,
                ]
            ),
        ]
    ]
);

Phalcon\Db::createTable() は、テーブルを表す連想配列を受けつけます。 Columns are defined with the class Phalcon\Db\Column. カラムの定義に使用できるオプションを次の表で示します。

オプション 説明 オプション
type カラムタイプ Must be a Phalcon\Db\Column constant (see below for a list) いいえ
primary そのカラムがテーブルのプライマリーキーの部分だった場合は true です。 はい
size VARCHARINTEGER のような種類のカラムは指定のサイズになります。 はい
scale DECIMAL または NUMBER カラムでサイズを指定します。どのくらい多くの桁を保持すべきかを示します。 はい
unsigned INTEGER カラムは符号付きまたは符号なしの可能性があります。 このオプションは他のタイプのカラムに適用されません。 はい
notNull カラムが、nullを格納できるかどうか。 はい
default デフォルト値 ('notNull' => trueの場合に使用する) はい
autoIncrement この属性を使用すると、オートインクリメントされた整数が自動的に入力されます。 テーブル内で1カラムだけ、この属性を持つことができます。 はい
bind BIND_TYPE _*定数の1つで、カラムをバインドしてから保存する必要があります はい
first このカラムは、最初の位置に置かれなければなりません。 はい
after このカラムは、指定されたカラムの後に置く必要があります。 はい

Phalcon\Db supports the following database column types:

  • Phalcon\Db\Column::TYPE_INTEGER
  • Phalcon\Db\Column::TYPE_DATE
  • Phalcon\Db\Column::TYPE_VARCHAR
  • Phalcon\Db\Column::TYPE_DECIMAL
  • Phalcon\Db\Column::TYPE_DATETIME
  • Phalcon\Db\Column::TYPE_CHAR
  • Phalcon\Db\Column::TYPE_TEXT

Phalcon\Db::createTable() に渡された連想配列は、次のキーを持てます:

インデックス 説明 オプション
columns An array with a set of table columns defined with Phalcon\Db\Column いいえ
indexes An array with a set of table indexes defined with Phalcon\Db\Index はい
references An array with a set of table references (foreign keys) defined with Phalcon\Db\Reference はい
options テーブルの作成オプションの配列。 これらのオプションは多くの場合、マイグレーションで生成されたデータベースシステムに関係します。 はい

テーブルの変更

アプリケーションが大きくなるにつれて、リファクタリングや新しい機能の追加の一環として、データベースを変更する必要が生じる場合があります。 すべてのデータベースシステムで既存のカラムを変更したり、既存のカラムの間にカラムを追加することはできません。 Phalcon\Db is limited by these constraints.

<?php

use Phalcon\Db\Column as Column;

// 新しいカラムの追加
$connection->addColumn(
    'robots',
    null,
    new Column(
        'robot_type',
        [
            'type'    => Column::TYPE_VARCHAR,
            'size'    => 32,
            'notNull' => true,
            'after'   => 'name',
        ]
    )
);

// 既存カラムの修正
$connection->modifyColumn(
    'robots',
    null,
    new Column(
        'name',
        [
            'type'    => Column::TYPE_VARCHAR,
            'size'    => 40,
            'notNull' => true,
        ]
    )
);

// 'name' カラムの削除
$connection->dropColumn(
    'robots',
    null,
    'name'
);

テーブルの削除

現在のデータベースから既存のテーブルをドロップするには、dropTable メソッドを使用します。 カスタム データベースからテーブルを削除するには、2 番目のパラメーターでデータベースの名前を指定します。 テーブル削除の例:

<?php

// アクティブなデータベースから 'robots' テーブルを削除
$connection->dropTable('robots');

// 'machines' データベースから 'robots' テーブルを削除 
$connection->dropTable('robots', 'machines');