Doctrineで論理削除を意識せずに扱う
こんにちは。小川です。
本日はDoctrineで論理削除を意識せずに扱う方法を紹介しようと思います。
結論から言うと、Doctrineが標準で用意しているSoftDeleteテンプレートをモデルに実装すれば自動的にクエリが発行する際に削除の判定を行ってくれるようになります。
テンプレートに関しては以前書いたブログがあるのでそちらを参考にしてください。
ただ上記の記事はDoctrine 0.11をベースに書いた記事なのですが、Doctrine 1.0からテンプレートの定義方法が少し変わったので先に少し説明します。
以前書いた記事では、config/doctrine/schema.ymlで
のようにtemplatesという名前で指定していましたが、templatesではなく「actAs」で指定するようになりました。
actAs自体は以前から存在しており、内容自体はほぼ同じです。
ちなみに以前書いたときはDoctrine_Template_Timestampableのように完全なクラス名を指定したのですが、クラスを生成する前にDoctrine_Template_で始まるクラスがあればそちらを使うような仕組みになっているためTimestampableと指定するだけでいいようです。
というわけで、論理削除をしたいモデルに対してschema.ymlで
上記のように記述すればSoftDeleteテンプレートが実装されます。
それではSoftDeleteテンプレートがどのようなことを行うのかを少し説明します。
SoftDeleteテンプレートを実装したモデルは自動的に
deletedカラムがモデルに追加され、trueの場合は削除として扱われるようになります。
検索時は、Doctrine_Queryのexecuteメソッドが実行されたタイミングで、(deleted = false OR deleted IS NULL)の条件が追加されます。もちろんエイリアスも張られます。
Doctrine_Tableに実装されているファインダメソッド(findXXX)や$article->getComments()などとやったときも内部でDoctrine_Queryが生成されるので
Doctrineのオブジェクトを取得する場合は大体大丈夫なのではないかと思います。
削除のときはDoctrine_QueryでDELETE文を発行する方法とRecordオブジェクトにdeleteメソッドを発行する方法が存在しますが、どちらの場合でもdeletedをtrueにUPDATEし、DELETEは行わないようになっています。
また、削除済みのものも検索で取得したい場合や物理削除を行いたい場合もあると思います。
これに関してはきれいな形での対応はされていないのですが、どちらもDoctrine_Queryでクエリを発行した場合にクエリにdeletedに関する記述がある場合はクエリを修正しないように作成されているため、
などの指定を追加してあげれば削除済みのレコードの検索や物理削除を行えます。
ただしこのときに
と書いた場合、クエリ中から"Article.deleted"を検索し記述がないものとして処理されるため、必ずエイリアスをつける必要があります。
ただしこれはSELECT限定で、DELETEのときはエイリアスがなくても動くようです。
ここまで実装方法などについて書いてきましたが、実はこれだけだと動きません。
Doctrineのデフォルトの設定では、Doctrine_Queryを実行前後で修正することが出来なくなっており、そこを設定してあげる必要があります。この設定の方法がsymfony 1.0とsymfony 1.1で変わってきます。
symfony 1.1ではProjectConfigurationクラスに設定を記述します。
上記のようにconfigureDoctrineメソッドでDoctrine::ATTR_USE_DQL_CALLBACKSをtrueにセットしなければいけません。
symfony 1.2でも同様です。というかsymfony 1.2でやったので上記がsymfony 1.1で動くかは実は検証してなかったりしますが、たぶん大丈夫だと思います。
symfony 1.0ではProjectConfigurationクラスはないのでどのようにやるかというと、sfDoctrinePlugin/configディレクトリの中にあるdoctrine.ymlをconfig直下にコピーしてきてそこに記述します。
attributes内にuse_dql_callbacksをtrueにする記述を追加すればOKです。ぶっちゃけこれも検証してないですがたぶん大丈夫だと思います。
SoftDeleteテンプレートについての説明は以上です。論理削除は全て自前で実装すると何かと面倒ですが、このテンプレートを使えばかなり楽になりそうですね。
Doctrineで論理削除を行う場合はぜひ使ってみてはいかがでしょうか。
本日はDoctrineで論理削除を意識せずに扱う方法を紹介しようと思います。
結論から言うと、Doctrineが標準で用意しているSoftDeleteテンプレートをモデルに実装すれば自動的にクエリが発行する際に削除の判定を行ってくれるようになります。
テンプレートに関しては以前書いたブログがあるのでそちらを参考にしてください。
ただ上記の記事はDoctrine 0.11をベースに書いた記事なのですが、Doctrine 1.0からテンプレートの定義方法が少し変わったので先に少し説明します。
以前書いた記事では、config/doctrine/schema.ymlで
- templates:
...
のようにtemplatesという名前で指定していましたが、templatesではなく「actAs」で指定するようになりました。
actAs自体は以前から存在しており、内容自体はほぼ同じです。
ちなみに以前書いたときはDoctrine_Template_Timestampableのように完全なクラス名を指定したのですが、クラスを生成する前にDoctrine_Template_で始まるクラスがあればそちらを使うような仕組みになっているためTimestampableと指定するだけでいいようです。
というわけで、論理削除をしたいモデルに対してschema.ymlで
- Article:
columns: ... actAs SoftDelete: {}
上記のように記述すればSoftDeleteテンプレートが実装されます。
それではSoftDeleteテンプレートがどのようなことを行うのかを少し説明します。
SoftDeleteテンプレートを実装したモデルは自動的に
deleted: { type: boolean, notnull: true, default: false }
deletedカラムがモデルに追加され、trueの場合は削除として扱われるようになります。
検索時は、Doctrine_Queryのexecuteメソッドが実行されたタイミングで、(deleted = false OR deleted IS NULL)の条件が追加されます。もちろんエイリアスも張られます。
Doctrine_Tableに実装されているファインダメソッド(findXXX)や$article->getComments()などとやったときも内部でDoctrine_Queryが生成されるので
Doctrineのオブジェクトを取得する場合は大体大丈夫なのではないかと思います。
削除のときはDoctrine_QueryでDELETE文を発行する方法とRecordオブジェクトにdeleteメソッドを発行する方法が存在しますが、どちらの場合でもdeletedをtrueにUPDATEし、DELETEは行わないようになっています。
また、削除済みのものも検索で取得したい場合や物理削除を行いたい場合もあると思います。
これに関してはきれいな形での対応はされていないのですが、どちらもDoctrine_Queryでクエリを発行した場合にクエリにdeletedに関する記述がある場合はクエリを修正しないように作成されているため、
- $query->addWhere("{$alias}.deleted
IS NOT NULL")
などの指定を追加してあげれば削除済みのレコードの検索や物理削除を行えます。
ただしこのときに
- Doctrine_Query::create()->from('Article')
->where('deleted IS NOT NULL')->execute(); - //
DQL => "FROM Article WHERE deleted IS NOT NULL"
と書いた場合、クエリ中から"Article.deleted"を検索し記述がないものとして処理されるため、必ずエイリアスをつける必要があります。
ただしこれはSELECT限定で、DELETEのときはエイリアスがなくても動くようです。
ここまで実装方法などについて書いてきましたが、実はこれだけだと動きません。
Doctrineのデフォルトの設定では、Doctrine_Queryを実行前後で修正することが出来なくなっており、そこを設定してあげる必要があります。この設定の方法がsymfony 1.0とsymfony 1.1で変わってきます。
symfony 1.1ではProjectConfigurationクラスに設定を記述します。
- class
ProjectConfiguration extends sfProjectConfiguration - {
protected $plugins = array('sfDoctrinePlugin'); public function configureDoctrine($manager) { $manager->setAttribute(Doctrine::ATTR_USE_DQL_CALLBACKS, true); } - }
上記のようにconfigureDoctrineメソッドでDoctrine::ATTR_USE_DQL_CALLBACKSをtrueにセットしなければいけません。
symfony 1.2でも同様です。というかsymfony 1.2でやったので上記がsymfony 1.1で動くかは実は検証してなかったりしますが、たぶん大丈夫だと思います。
symfony 1.0ではProjectConfigurationクラスはないのでどのようにやるかというと、sfDoctrinePlugin/configディレクトリの中にあるdoctrine.ymlをconfig直下にコピーしてきてそこに記述します。
- all:
attributes: use_dql_callbacks: true
attributes内にuse_dql_callbacksをtrueにする記述を追加すればOKです。ぶっちゃけこれも検証してないですがたぶん大丈夫だと思います。
SoftDeleteテンプレートについての説明は以上です。論理削除は全て自前で実装すると何かと面倒ですが、このテンプレートを使えばかなり楽になりそうですね。
Doctrineで論理削除を行う場合はぜひ使ってみてはいかがでしょうか。
トラックバックURI
最近の記事
システム開発エンジニア募集! [2012年02月03日 : 小林有佳]
OpenVPNで細々便利な設定 [2012年01月31日 : 門脇優児]
【iOS】Viewの開発・デバッグに役立つ色々 [2012年01月23日 : 中川善樹]
PHPDocumentorの利用方法まとめ [2012年01月19日 : 笹亀弘]
Google Chart Toolsを使ってサイトマップを描こう! [2011年12月21日 : 志田仁美]
stumpwm設定v2 [2011年12月19日 : 門脇優児]
Mashup Awards 7の授賞式が行われました [2011年12月16日 : 中川善樹]
社員旅行に行きました [2011年12月12日 : 大橋寛子]
iCloud風のアイコンを作成する(Fireworks) [2011年12月07日 : 和田記光]
iScroll4でネイティブに近いスマホ向けHTMLページを作成する [2011年12月02日 : 松田惇]













コメントフォーム