Doctrineは属性を利用して機能と機能性を制御します。このセクションではDoctrineの機能性を使うために、属性の設定と取得する方法および、存在する属性をオーバーライドする方法を検討します。
Doctrineは3レベルの設定構造を持ちます。グローバル、接続とテーブルレベルで設定属性を設定できます。同じ属性が下側と上側の両方のレベルで設定される場合、一番上の属性が常に使われます。例えばユーザーが最初にグローバルレベルでデフォルトの取得モードをDoctrine_Core::FETCH_BATCHに設定してテーブルの取得モードをDoctrine_Core::FETCH_LAZYに設定すれば、遅延取得戦略はテーブルのレコードが取得されているときはいつでも使えます。
次の例ではグローバルレーベルで1つの属性を設定します:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_VALIDATE, Doctrine_Core::VALIDATE_ALL);
次の例は与えられた接続のグローバル属性をオーバーライドします:
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_VALIDATE, Doctrine_Core::VALIDATE_NONE);
最後の例ではテーブルレベルで接続レベルの属性を再度オーバーライドします:
// bootstrap.php
// ...
$table = Doctrine_Core::getTable('User');
$table->setAttribute(Doctrine_Core::ATTR_VALIDATE, Doctrine_Core::VALIDATE_ALL);
Doctrine_Core::getTable()メソッドを使った例は紹介しませんでした。次の章の[doc component-overview:table :name]のセクションでテーブルオブジェクトを詳しく学びます。
それぞれのデータベース管理システム(DBMS - Database Management System)は独自の振る舞いを行います。例えば、出力する際にテーブルの名前の最初の文字を大文字にするものもがあれば、小文字にしたりそのままにするものがあります。これらの挙動によってアプリケーションを別の種類のデータベースに移植させるのが難しくなります。Doctrineはこれらの困難に打ち勝つために努力してくれるのでアプリケーションを変更せずにDBMSを切り替えることができます。例えばsqliteからmysqlに切り替えることです。
ポータビリティモードはビット単位なので、|を使い結合したり^を使い削除できます。これを行う方法の例は下記のセクションをご覧ください。
ビット演算子の詳細な情報はPHP公式サイトをご覧ください。
すべてのポータビリティ属性と説明の一覧です:
| 名前 | 説明 | |
|---|---|---|
| PORTABILITY_ALL | すべてのポータビリティモードを有効にする。これはデフォルトの設定です。 | |
| PORTABILITY_DELETE_COUNT | 削除される列の数のレポートを強制する。シンプルなDELETE FROMテーブル名のクエリを実行する際に削除される列の数をカウントしないDBMSがあります。このモードではDELETEクエリの最後にWHERE 1=1を追加することでRDBMSをだましてカウントするようにします | |
| PORTABILITY_EMPTY_TO_NULL | データと出力において空の文字列の値をnullに変換する。必要なのはOracleは空の文字列をnullと見なす一方で、その他の主なDBMSは空とnullの違いを知っているからです。 | |
| PORTABILITY_ERRORS | 特定のドライバの特定のエラーメッセージを他のDBMSと互換性があるようにする | |
| PORTABILITY_FIX_ASSOC_FIELD_NAMES | これは連想配列形式の取得においてキーから修飾子を削除します。SQLiteなどは、クエリで省略されていない場合に連想配列形式のカラムに対して省略されていない名前をデフォルトで使用します。 | |
| PORTABILITY_FIX_CASE | すべてのメソッドで小文字もしくは大文字にするためにテーブルとフィールドの名前を変換する。事例はfield_caseオプションに依存しCASE_LOWER(デフォルト)もしくはCASE_UPPERのどちらかに設定できます。 | |
| PORTABILITY_NONE | すべてのポータビリティ機能を無効にする。 | |
| PORTABILITY_NUMROWS | OracleでnumRows()を動作させるためのハックを有効にする | |
| PORTABILITY_EXPR | ポータブルではない式が使われる場合にDQL APIが例外を投げる。 | |
| PORTABILITY_RTRIM | すべてのデータ取得する際にデータ出力の右トリミングする。固定長の文字の値を右トリミングしない場合でも、これは固定長の文字の値を自動的に右トリミングするRDBMSには適用されない。 |
小文字化とトリミングのためにポータビリティモードを有効にするsetAttribute()メソッドを次のコードのように使うことができます:
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_PORTABILITY,
Doctrine_Core::PORTABILITY_FIX_CASE | Doctrine_Core::PORTABILITY_RTRIM);
トリミングを除いたすべてのポータビリティモードを有効にする
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_PORTABILITY,
Doctrine_Core::PORTABILITY_ALL ^ Doctrine_Core::PORTABILITY_RTRIM);
quoteIdentifier()でDBの識別子(テーブルとフィールド名)をクォートできます。区切りのスタイルはデータベースドライバによります。
区切られた識別子を使うことができるので、これらを使うべきであることを意味しません。一般的に、これらが解決する問題よりも多くの問題を引き起こします。ともかく、フィールドの名前として予約語がある場合に必要です(この場合、できるのであれば、予約語を変更することを提案します)。
Doctrineの内部メソッドの中にはクエリを生成するものがあります。quote_identifier属性を有効にすることで、これらの生成クエリの中で識別子をクォートするようDoctrineに伝えることができます。すべてのユーザー提供のクエリに対してこのオプションは無意味です。
区切られた識別子内部で次の文字を使うとポータビリティが壊れます:
| 名前 | 文字 | ドライバ |
|---|---|---|
| backtick | ` | MySQL |
| double quote | " | Oracle |
| brackets | [ or ] | Access |
次のドライバの元で識別子の区切りが一般的に正しく動作することが知られています: Mssql、Mysql、Oracle、Pgsql、SqliteとFirebird
Doctrine_Core::ATTR_QUOTE_IDENTIFIERオプションを使うとき、フィールドの識別子のすべては結果のSQL文において自動的にクォートされます:
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_QUOTE_IDENTIFIER, true);
結果のSQL文においてすべてのフィールド名はバッククォート演算子'`'でクォートされます(MySQL)。
SELECT
*
FROM sometable
WHERE `id` = '123'
対照的に:
SELECT
*
FROM sometable
WHERE id = '123'
デフォルトではあたかもすでに問い合わせされ修正されたオブジェクトを問い合わせしたようにDoctrineはオブジェクトでのローカルの変更を上書きするように設定されています。
$user = Doctrine_Core::getTable('User')->find(1);
$user->username = 'newusername';
上記のオブジェクトを修正したのであたかも同じデータを再度問い合わせしたように、ローカルな変更は上書きされます。
$user = Doctrine_Core::getTable('User')->find(1);
echo $user->username; // データベースのオリジナルのユーザー名を出力する
`ATTR_HYDRATE_OVERWRITE`属性を使うことでこのふるまいを無効にできます:
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_HYDRATE_OVERWRITE, false);
これで上記で同じテストを実行したとしても、修正されたユーザー名は上書きされません。
`Doctrine_Core::getTable()`メソッドを使うときに返されるクラスを設定したい場合`ATTR_TABLE_CLASS`属性をセットできます。唯一の要件は`Doctrine_Table`を継承するクラスです。
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_TABLE_CLASS, 'MyTableClass');
`MyTableClass`は次のようになります:
class MyTableClass extends Doctrine_Table
{
public function myMethod()
{
// 何らかのクエリを実行し結果を返す
}
}
これで次のコードを実行するとき`MyTableClass`のインスタンスが返されるようになります:
$user = $conn->getTable('MyModel')->myMethod();
テーブルクラスをさらにカスタマイズしたい場合それぞれのモデルごとにカスタマイズできます。
`MyModelTable`という名前のクラスを作りオートロード可能であることを確認します。
class MyModelTable extends MyTableClass
{
public function anotherMethod()
{
// 何らかのクエリを実行し結果を返す
}
}
次のコードを実行するとき`MyModelTable`のインスタンスが返されます:
echo get_class($conn->getTable('MyModel')); // MyModelTable
新しいクエリインスタンスを作るとき基底のクエリクラスを設定したいとき、`ATTR_QUERY_CLASS`属性を使うことができます。唯一の要件は`Doctrine_Query`クラスを継承することです。
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_QUERY_CLASS, 'MyQueryClass');
`MyQueryClass`は次のようになります:
class MyQueryClass extends Doctrine_Query
{
}
これで新しいクエリを作ると`MyQueryClass`のインスタンスが返されるようになります:
$q = Doctrine::getTable('User')
->createQuery('u');
echo get_class($q); // MyQueryClass
基底クラスとテーブルクラスを設定できるので、Doctrineが使うコレクションクラスもカスタマイズできることのみに意味をなします。`ATTR_COLLECTION_CLASS`属性をセットする必要があるだけです。
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_COLLECTION_CLASS, 'MyCollectionClass');
`MyCollectionClass`の唯一の要件は`Doctrine_Collection`を継承しなければならないことです:
$phonenumbers = $user->Phonenumber;
echo get_class($phonenumbers); // MyCollectionClass
オプションとして利便性のために`ATTR_CASCADE_SAVES`属性によってデフォルトで有効になっているカスケーディングセーブオペレーションを無効にできます。この属性を`false`にするとレコードがダーティである場合のみカスケードとセーブが行われます。このことは階層において1つのレベルより深くダーティなレコードをカスケードしてセーブできないことを意味しますが、顕著なパフォーマンスの改善の効果を得られます。
$conn->setAttribute(Doctrine::ATTR_CASCADE_SAVES, false);
テーブル作成用にデータベースにクラスをエクスポートする際にDoctrineにエクスポートするものを伝えるためにエクスポート属性が使われます。
何もエクスポートしたくない場合は次のように行います:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_EXPORT, Doctrine_Core::EXPORT_NONE);
(制約は伴わずに)テーブルだけをエクスポートするためだけなら次のようにできます:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_EXPORT, Doctrine_Core::EXPORT_TABLES);
上記と同じ内容を次の構文でも実現できます:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_EXPORT,
Doctrine_Core::EXPORT_ALL ^ Doctrine_Core::EXPORT_CONSTRAINTS);
すべて(テーブルと制約)をエクスポートするには:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_EXPORT, Doctrine_Core::EXPORT_ALL);
命名規約の属性は、テーブル、インデックスとシーケンスのような要素に関連する異なるデータベースの命名に影響を及ぼします。データベースからクラスまでのスキーマをインポートするときとクラスをデータベーステーブルにエクスポートするとき、基本的にすべての命名規約属性は両方の方法で影響を及ぼします。
例えばDoctrineのインデックス用の命名規約のデフォルトは%s_idxです。インデックスだけでなく特別な接尾辞を設定可能で、インポートされるクラスは接尾辞を持たない対応物にマッピングされるインデックスを取得します。これはすべての命名規約属性に適用されます。
Doctrine_Core::ATTR_IDXNAME_FORMATは命名規約のインデックスを変更するために使われます。デフォルトではDoctrineは[name]_idxのフォーマットを使用します。'ageindex'と呼ばれるインデックスの定義は実際には'ageindex_idx'に変換されます。
次のコードでインデックスの命名規約を変更できます:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_IDXNAME_FORMAT, '%s_index');
Doctrine_Core::ATTR_IDXNAME_FORMATと同じように、Doctrine_Core::ATTR_SEQNAME_FORMATはシーケンスの命名規約を変更するために使うことができます。デフォルトではDoctrineは[name]_seqのフォーマットを使います。mysequenceの名前を持つ新しいシーケンスを作るとmysequence_seqという名前のシーケンスに作成につながるからです。
次のコードでシーケンスの命名規約を変更できます:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_SEQNAME_FORMAT, '%s_sequence');
インデックスとシーケンス名のフォーマットと同じようにテーブル名のフォーマットは次のコードで変更できます:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_TBLNAME_FORMAT, '%s_table');
インデックス、シーケンスとテーブル名のフォーマットと同じようにデータベース名のフォーマットを次のコードで変更できます:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_DBNAME_FORMAT, 'myframework_%s');
Doctrineはバリデーションに対して完全なコントロール機能を提供します。バリデーション処理はDoctrine_Core::ATTR_VALIDATEでコントロールされます。
バリデーションモードはビット単位なので、|を使用して結合し^を使用して削除できます。これを行う方法は下記の例をご覧ください。
| 名前 | 説明 |
|---|---|
| VALIDATE_NONE | バリデーション処理全体をオフに切り替える。 |
| VALIDATE_LENGTHS | すべてのフィールドの長さをバリデートする。 |
| VALIDATE_TYPES | すべてのフィールドの型をバリデートする。Doctrineは緩い型のバリデーションを行う。例えば'13.3'などを含む文字列は整数としてパスしないが'13'はパスする。 |
| VALIDATE_CONSTRAINTS | notnull、emailなどのすべてのフィールド制約をバリデートする。 |
| VALIDATE_ALL | すべてのバリデーションをオンにする。 |
デフォルトのバリデーションは無効になっているのでデータをバリデートしたい場合有効にする必要があります。この設定を変更する方法の例のいくつかは下記で示されています。
次のコードでDoctrine_Core::VALIDATE_ALL属性を利用してすべてのバリデーションを有効にできます:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_VALIDATE, Doctrine_Core::VALIDATE_ALL);
次のコードで長さと型をバリデートし、制約には行わないようにDoctrineを設定できます:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_VALIDATE,
Doctrine_Core::VALIDATE_LENGTHS | Doctrine_Core::VALIDATE_TYPES);
Doctrineを設定するために最も良く使われる属性の一部を検討してきました。今のところこれらの属性はよくわからないかもしれません。次の章を読めば必要な属性がわかります。
上記の値を変更したい属性がありましたら、これをbootstrap.phpファイルに追加するとコードは次のようになります:
/**
* Bootstrap Doctrine.php, register autoloader and specify
* configuration attributes
*/
require_once('../doctrine/branches/1.2/lib/Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));
$manager = Doctrine_Manager::getInstance();
$conn = Doctrine_Manager::connection('sqlite::memory:', 'doctrine');
$manager->setAttribute(Doctrine_Core::ATTR_VALIDATE, Doctrine_Core::VALIDATE_ALL);
$manager->setAttribute(Doctrine_Core::ATTR_EXPORT, Doctrine_Core::EXPORT_ALL);
$manager->setAttribute(Doctrine_Core::ATTR_MODEL_LOADING, Doctrine_Core::MODEL_LOADING_CONSERVATIVE);
次の章に移動する準備ができました。DoctrineのConnectionsに関するすべての内容を学びます。