Bug(バグ) #2911
完了プラグイン無効時にデータ削除を伴う操作でエラーやデータ不整合が発生する
0%
説明
Overview (現象)¶
プラグイン無効時に退会などのデータ削除を伴う処理がエラーとなり操作できない場合がある。
例:
- opCommunityTopicPlugin 無効時、退会処理を行うと500エラーとなり退会できない
- opCommunityTopicPlugin 無効時、コミュニティ削除処理を行うと500エラーとなり削除できない
- opCommunityTopicPlugin 無効時、画像削除を行うと500エラーとなり削除できない(プロフィール画像や日記画像などコミュニティトピックと関係のない画像であってもエラーになる)
バンドルプラグインでは opCommunityTopicPlugin だけであるが、schema.yml で actAs を使ってプラグイン内のクラスを指定している場合、同様の問題が発生する。
また、プラグイン無効時にはエラーとはならないがデータ不整合が発生し、再有効化後に問題が発生する場合がある。
例:
- opIntroFriendPlugin 無効化中に紹介文の存在するフレンド関係を削除し、再度 opIntroFriendPlugin を有効化すると、フレンドではないメンバーの紹介文が削除されておらず表示されてしまう
Causes (原因)¶
Doctrine により自動生成されるモデルはプラグインの有効・無効を考慮しないため、無効なプラグインのモデルを利用するコードが生成される。例として relation 関係のあるモデルの削除処理の過程で利用される(削除以外の処理で利用されるかどうかの網羅的な調査はできていない)。これにより単純な onDelete: cascade などのデータ整合性を保つための処理がプラグイン無効時にも動作するというメリット(?)はある。
一方、無効なプラグイン内のファイルに含まれるクラスライブラリはオートロードの対象から外れるため、それを呼び出すコードを実行すると Fatal Error となり PHP の実行は停止され、クライアントへは結果として 500 エラーが返される。
opCommunityPlugin のように schema.yml 内で actAs にプラグイン内のクラスが指定されている場合、これに該当し関連するモデル(この例では Member, Community, File)の削除処理において Fatal Error が発生する。
また、プラグイン内でイベントハンドラによりコア側や他プラグインの動作タイミングでデータ更新をしている場合には、プラグイン無効時にイベントハンドラが呼び出されないため、データの不整合が発生する。opIntroFriendPlugin はフレンド削除のタイミングで、op_action.post_execute_friend_unlink イベントを利用し(onDelete: cascade のようなDB上の制約を使わずに)データ削除を行なっているため、このケースに該当する。
Way to fix (修正内容)¶
プラグインの有効・無効の切り替え機能を完全に機能させる前提での修正が難しいため、管理者がそのことを理解した上でこの機能を利用できるように画面上に注意文を追加する対応とする。
機能自体を削除することも検討したが、問題なく有効・無効を切り替えられるプラグインも多いため、安定版での機能削除は不適当と判断した。削除するのであれば別途 Enhancement チケットを作成して開発版のみで対応すべきと考える。
補足として、プラグインの有効・無効の切り替え機能を完全に機能させることが難しい理由を以下に記す。
プラグインを 有効 → 無効 → 有効 と切り替えた際に正常な動作を保証するのが困難で、無効な状態の際にデータの更新処理をどのようにおこなうか(おこなわないか)が課題となる。
データの整合性を保つためには無効なプラグインに関するデータの更新処理をおこなう必要があり、そのためにはプラグイン下のライブラリやDB上のテーブル間の制約を動作させる必要がある。ただし、データの整合性を保つための機能だけを動作させるというのはコア側から一定のルールで切り分けができるものではなく、必要以上に動作してしまう部分が出てくる懸念があるため、各プラグインでもなんらかの実装を合わせてする必要がある可能性が高い。例えば、プラグイン内のイベントハンドラによる処理などは基本的にどんな処理でも書ける仕様であるため、コア側で無効時にどの処理が必要かを判別する術がない。逆にコア側のオートロードの仕組みを変えない限りはプラグイン側だけで解決できる問題でもない。なんとか制御する仕組みが作れたとしてもコア、プラグイン共に変更は大規模となりプラグイン側の後方互換性を損なう恐れもある。
データの整合性を諦めて無効なプラグインのデータの更新処理はおこなわない方針を目指したとしても、少なくとも Doctrine のモデル、DB テーブルの外部キー制約を改変する必要がありこれだけでも簡単ではない。特に外部キーは再有効化時にデータ不整合で戻せない可能性もある。そもそもこの方針が上手く行ったところで再有効化時に正常動作する保証はないため、プラグインの有効・無効切り替えが正常動作しているとは言い難い。
参考情報¶
http://sns.openpne.jp/communityTopic/8139 より転記
(1) OpenPNEのバージョン OpenPNE 3.6 (2) サーバ情報 CentOS 5.7 PHP 5.3.3 MySQL 5.0 (3) 現象の詳細 opCommunityTopicPlugin を無効にすると退会処理でエラー。 ( opCommunityTopicPlugin 1.0.2.2 ) 再現手順: 1.opCommunityTopicPlugin を無効にする。 2.管理画面から強制退会処理 or ユーザが退会処理を行う => 500エラー発生。 発生個所は、 /root/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Relation/Parser.php メソッド: getRelations() line: 250 再現しない場合、複合的な要因かもしれません。 とりあえず opCommunityTopicPlugin を有効にしておくことで回避できますが、参考までのご報告です。
Yuma Sakata さんが12年以上前に更新
再現確認できました。
Environment (再現バージョン)¶
OpenPNE 3.6.2
opCommunityTopicPlugin 1.0.3.1
Way to repro (再現手順)¶
1. 管理画面アプリケーションプラグイン設定ページ(/pc_backend.php/plugin/list)にアクセスする
2. opCommunityTopicPlugin を無効に設定する
3. メンバーリストページ(/pc_backend.php/member)から、任意のメンバーを強制退会する
4. 退会処理でエラーが発生して、強制退会できない
Way to fix (修正内容)¶
opCommunityTopucPlugin を無効に設定後、退会処理が実行できるように修正お願いします。
Yuya Watanabe さんが12年以上前に更新
- ステータス を New(新規) から Accepted(着手) に変更
- 担当者 を Yuya Watanabe にセット
Yuya Watanabe さんが12年以上前に更新
エラー内容
PHP Fatal error: Class 'opCommunityTopicPluginImagesBehavior' not found in **/lib/model/doctrine/opCommunityTopicPlugin/base/BaseCommunityTopic.class.php on line 94
lib/model/doctrine/opCommunityTopicPlugin/base/BaseCommunityTopic.class.php 94 行目
92 'foreign' => 'community_topic_id')); 93 94 $opcommunitytopicpluginimagesbehavior0 = new opCommunityTopicPluginImagesBehavior(); 95 $timestampable0 = new Doctrine_Template_Timestampable(); 96 $this->actAs($opcommunitytopicpluginimagesbehavior0);
config/doctrine/schema.yml
5 CommunityTopic: 6 actAs: 7 opCommunityTopicPluginImagesBehavior: 8 Timestampable: 9 columns: 10 id: { type: integer(4), primary: true, autoincrement: true } 11 community_id: { type: integer(4), notnull: true } 12 member_id: { type: integer(4) } 13 name: { type: string, notnull: true } 14 body: { type: string, notnull: true } 15 topic_updated_at: { type: timestamp } 16 relations: 17 Member: 18 onDelete: set null 19 Community: 20 onDelete: cascade
Yuya Watanabe さんが12年以上前に更新
note-4 の内容を考慮すると,削除する際にロードされるべきクラスがロードされていないことが原因であると思われるため,本体側の問題であると思います.
Yuma Sakata さんが12年以上前に更新
- プロジェクト を opCommunityTopicPlugin から OpenPNE 3 に変更
- 対象バージョン を削除 (
1.0.4)
Yuya Watanabe さんが12年以上前に更新
- ステータス を Accepted(着手) から Pending Fixing(修正待ち) に変更
- 担当者 を削除 (
Yuya Watanabe)
Yuma Sakata さんが約12年前に更新
- 対象バージョン を OpenPNE 3.8.2 から OpenPNE 3.9.0-old に変更
- 3.8 で発生するか を Unknown (未調査) にセット
Rimpei Ogawa さんがほぼ12年前に更新
- 題名 を opCommunityTopicPlugin無効後、退会処理を行うとエラーになる から プラグイン無効時にデータ削除を伴う操作でエラーやデータ不整合が発生する に変更
- 説明 を更新 (差分)
- ステータス を Pending Fixing(修正待ち) から Accepted(着手) に変更
- 3.8 で発生するか を Unknown (未調査) から Yes (はい) に変更
Description を更新しました。
Rimpei Ogawa さんがほぼ12年前に更新
- ステータス を Accepted(着手) から Pending Review(レビュー待ち) に変更
- 進捗率 を 0 から 50 に変更
更新履歴 08f6e9fb192615807bb1e9a8d6d2be404e5f5bcb で適用されました。
Rimpei Ogawa さんがほぼ12年前に更新
プラグイン無効時の問題の回避策として「プラグインの削除」を説明する必要があったため、当初管理画面上にプラグインの削除手順を記載する方法を検討しましたが、以下の理由により管理画面上には詳細説明を載せず、インストール・アンインストール手順を説明するための新しいドキュメントを作成する方法を採りました。
- 管理画面上の既存のプラグインインストール手順の説明には不足があり、プラグインによっては正常にインストールを完了することができない問題があったこと
- プラグインのインストール・アンインストール手順を正確に書こうとすると、プラグインリストと同一画面で説明するには長くなりすぎること
- サーバー上のソースコードの管理はおこなわず管理画面のみを利用する管理者にとっては、プラグインのインストール・アンインストールの詳細手順は全く必要ないものであること
Kousuke Ebihara さんがほぼ12年前に更新
- ステータス を Pending Review(レビュー待ち) から Pending Testing(テスト待ち) に変更
- 進捗率 を 50 から 70 に変更