Mantis Bug Trackerのカスタマイズ方法について

# Mantisをカスタマイズするにあたって

Mantisは言わずと知れたバグトラッキングシステムです。

[MantisBT](http://www.mantisbt.org)

オープンソースのソフトウェアで、言語がPHPで作られているので、自由にカスタマイズが可能です。

関数単位でカスタマイズする場合は、以下のオフィシャルガイドに書かれているカスタムファンクション機能を使います。

[Custom Functions](https://www.mantisbt.org/manual/admin.customize.customfuncs.html)

ここの説明に沿って、動きを変えたい関数をオーバーライドする関数を定義すると、そちらが動いてくれるという訳です。

ただ今回は関数単位ではなくて、画面の中の操作に対して、別の関数を条件によってコールしたいという場合なので上記の手法は使えません。
なのでMantisBTのコアを改造してみました。

# 利用したツール

MantisBTはオブジェクト指向で書かれているので、ソースを追いかける時にIDEが無いと辛いです。

なので今回は無料のNetBeansを使用してみました。

[NetBeans](https://ja.netbeans.org)

NetBeansでプロジェクトを作り、以下からダウンロードしたMantisBTのソースをインポートするだけでOKでした。

[MantisBT Download](http://www.mantisbt.org/download.php)

あとは、ソースを開いて調べたい定義等をマウスとクリック操作だけで追いかけられます。
viで開いてgrepを駆使してトレースするよりは、遥かに便利で時短になります。

# 要求仕様

バグチケットを画面操作で他の人にアサインする時に、担当者だった人をチケットの監視者に自動で追加したい！

Mantisの仕様では、他の人に担当者を変えると、元々の担当者には以後は何もメール通知が行われません。
元の担当者に見て欲しくてコメント書いても、メールが飛ばないので気づいてもらえなくて困るという訳です。
そこでチケット監視者にはメールが飛ぶという機能を利用して、担当者変えても強制的に気づけるように監視者に入れてしまえ！という訳です。

# ソース解析開始

MantisBTのソースの構造を熟知しているメンテナーでもない限り、どこをどういじればいいのかすぐには分からないと思います。

アプローチの仕方としては、まずは担当者を変更する画面を表示している時の、phpのソース名を見て、そこからトレースを開始する感じです。

## バグ更新画面での解析

まずブラウザで開いたURLを見ると「bug_update_page.php」となっているので、ソースを開いてみます。
すると以下が書かれているだけでした。

```php:bug_update.php
require_once( 'core.php' );

include 'bug_update_advanced_page.php';
```

実際のページ表示処理はincludeしているphpでやってそうですね。
次にそのソースを開いてみると、695行にも渡るコードが出てきました。

全体を眺めてみると、ページ全体が巨大なフォームになっていて、更新ボタンを押すことによって画面全体がPOSTされるような作りになっていることが分かります。

担当者を表示している部分を探してみると、コメントで以下が書かれている箇所がそれっぽいです。

`# Assigned To, Due Date`

ここでselectタグを使って担当者のリストを表示できるようにしたりしてるみたいです。

そして更新ボタンを押した時にPOSTする先はどこかというと、フォームの先頭を見れば分かります。

`echo '<form name="update_bug_form" method="post" action="bug_update.php">';`

bug_update.phpにフォームの内容を投げて処理させてるみたいです。
なので次はそのPHPを開いてみます。

何やら色々と処理が書いてありますが、通常のPOSTを受け取る処理がベタ書きされてはおらず、どこでどう受け取ってるのかを追うのは難儀しそうな感じです。

ただ以下のコメント文の下で、大量のデータを右から左に代入している処理がありました。

`# extract current extended information`

右がPOSTされてきた更新データで、左が現在のデータが入っている構造体だろうと予測してみました。
担当者については、以下でやってそうです。

`$t_bug_data->handler_id = gpc_get_int( 'handler_id', $t_bug_data->handler_id );`

この代入処理が行われる直前にif文で右と左の値が同じで無ければ、代入前のhandler_idを監視者に追加するという
処理を書いて実際に画面での操作をやってみたところ、ビンゴでした(笑)

監視者追加のAPIについては、ソースを眺めている時に見つけたそれっぽい名前の関数の定義にジャンプして見つけていましたが、bug_api.phpで定義されています。

`function bug_monitor( $p_bug_id, $p_user_id )`

引数にバグのIDと監視者にしたいユーザIDを渡すだけです。

結果的には、以下のコードを追加するだけでやりたいことを実現できました。

```php:bug_update.php
$t_new_handler_id = gpc_get_int( 'handler_id', $t_bug_data->handler_id );
if( $t_bug_data->handler_id != $t_new_handler_id ) {
  bug_monitor( $f_bug_id, $t_bug_data->handler_id );
}
```

if文の前に一度代入していますが、新しい担当者のIDが入ってるよ！というのを後で見て分かりやすくしたかったので、変数を追加してnewと付けただけです。

## バグ閲覧画面での解析

バグ閲覧画面で、フッターメニューの表示を有りにしていた場合に、閲覧画面から直接担当者を変更できるルートがあります。

そこで同じようなアプローチ手法を使ってソースを追ってみました。

bug_view_page.php -> view.php　-> bug_view_inc.php

と追って、やっとページ表示処理にたどり着きました。

フッターのボタンメニューの表示は以下でやってそうです。

html_buttons_view_bug_page()
※html_api.phpで定義されている

上記の処理の中では、更に以下をコールしていました。

html_button_bug_assign_to()
※これもhtml_api.phpで定義されている

ここでようやくフォームを表示する処理にたどり着きました。

フォームのポスト先は以下のecho文でbug_assign.phpだと分かります。

`echo "<form method=\"post\" action=\"bug_assign.php\">";`

そしてPOST先のソースを開いてみると、以下のコメント部分に処理を発見しました。

`# Update handler and status`

ここで以下の代入処理をしてしまう前に比較して、先ほどと同じ処理を追加すればOKでした。

`$t_bug->handler_id = $f_handler_id;`

# おわりに

今回Manntisのコアのカスタマイズをやりましたが、結論にたどり着いてしまえば単純な処理追加だけで実現できました。
ただ、そこにたどり着くまでのプロセスが非常に大変で、カンが外れたら結構ハマったかもしれません。

ただ、アプローチ方法さえ間違わなければ、今回のように割と短時間で結論に到達できると思います。
あまりMantisのコアを改造したいケースは無いかもしれませんが、やりたくなった場合の手法の参考になれば幸いです。