共通カテゴリモジュール

20 views
Skip to first unread message

氷川 霧霞

unread,
Jan 18, 2008, 8:43:02 PM1/18/08
to XOOPS Cube Developers Group Japan
モジュール間で共通に使えるカテゴリ管理用のモジュールを作ろうかなあと思っています。
多くのモジュールでカテゴリ的なものを持つことになりますし,その大半は共通に作れそうかなあと思いまして。

狙いは,
・モジュールを作るたびにカテゴリ関連の管理機能(カテゴリを追加したり親子関係を管理したり)を作らなくても済むようにしたい
・共通カテゴリに対応したモジュール間で,一つのカテゴリを共有できるようにすることで,ユーザのカテゴリ管理の手間を省く(特に権限設定など)

想定している機能としては,
・GIJOEさんのPicoについているカテゴリ管理機能とだいたい同じ。カテゴリの親子関係,カテゴリごと,アクションごとの権限設定など
・カテゴリの種類は複数設定可能。ニュース用カテゴリ,フォーラム用カテゴリなど,(必要な場合は)複数のカテゴリセットを作ることが出来る。カテゴリ
管理機能を利用するモジュール側は,どのカテゴリセットを利用するかを一般設定などで選択。

まだあまり深く考えていないのですが,僕が作ると Cube 専用になりますし,他に「自分が作りたい」「いま作っている」「既に作った」という方がい
らっしゃいましたら無駄なことをしなくて済むので教えていただければ幸いです m(__)m。

ITOH Takashi

unread,
Jan 23, 2008, 9:37:56 AM1/23/08
to xcube-...@googlegroups.com
伊藤です。

確かに、これあると便利です。

で、これを
XCube_DelegateUtils::call($kili_cat, 'as_array')
とかで簡単に呼べるといいですねー。

んで、$kili_cat[0]->checkAuth();とか。

この辺て、モジュール間通信のインターフェイスそのものだと思うんですが、
開発者用のドキュメントが欲しい・・・。というか、それが無いと意味無いですよね?
(とか押し付けがまし気に言う :-p

伊藤

minahito

unread,
Jan 26, 2008, 10:43:01 PM1/26/08
to xcube-...@googlegroups.com
minahito です。

この場合、カテゴリモジュール側にカテゴリの保存や管理等の機能が
ひとそろいあるため、他のモジュールが連携するにはデリゲートの他
に仮想サービスも使えるかもしれません。


【おおむねの目安】
○デリゲート
本体がプログラムを持って"いない"ので、
他のプログラムを呼び出して処理を代行させる。

使用モジュール側からすると、「機能」を呼ばれる側。
ただしメソッドの抽象化の一面を持つため、さまざまな応用が可能。

○仮想サービス
本体がプログラムを持っていて、
他のプログラムは API を通じて処理の成果を享受できる。

使用モジュール側からすると、「機能」を呼ぶ側。
現状 Cube 層で想定している唯一の「アドオンによるAPIの増設」


管理画面ではデリゲートをうまく使う。
カテゴリモジュールが考える「1オブジェクト」のデータ型を
各モジュールから返してもらう場合等は、各モジュールに委譲
しないとダメなので、デリゲートになると思います。

一方で通常の処理、
たとえば、モジュール側で、もしサイトにカテゴリモジュールが
入っていれば、表示中の記事の格納先を表示する...というような
場面では、サービスになると思います。

$serviceMgr =& $g_root->getServiceManager();
$service =& $serviceMgr->getService("CategoryService");

if ($service) {
$client =& $serviceMgr->createClienet($service);
// 自分の記事の所属情報を貰う
$hoge = $client->call("GetCategory", $this->getCategoryObject());
}


な の で す が、
仮想サービスは接続先がサイトであっても、モジュールであってもよく、かつ、
通信手段が SOAP 以外でもいけるような想定になっていて、モジュール間通信
としては直感的ではないという意見もちょろっと貰ってます。

最大のポイントは、仮想サービスを作るとそのまま Web サービスが作れること
ですが、ということは少なくとも Web サービスを作る程度の手数が必要だとい
うことです。


それで(話が変わっていくのですが)
7月を予定しているメジャーバージョンで、
従来、コアによって定義されていた数個のマネージャークラスとは別に、
自由なオブジェクトをルートに預けておける機能をつけてはどうかという
アイデアを出しています。

http://sourceforge.net/forum/forum.php?thread_id=1919905&forum_id=537172

この場合、カテゴリモジュールのプリロードでカテゴリサービスのオブジェ
クトを作ってルートに預け、使う側はルートから取り出して使います。

メリットは、仮想サービスより直感的だということ。
ほぼ、グローバル変数の世界です。
狂った仕様のようですが、実は .NET Framework の一部でこういう仕様があり
ます。

GraphicsDeviceManager =
(GraphicsDeviceManager)GetService("GraphicsDeviceManager");

Getならともかく、あるインターフェイスをもつオブジェクトを、 Object クラス
までアップキャストして Setして、それでフレームワーク側と通信するような
仕様になってます。
そこで Hoge とか関係ないクラスのオブジェクトを入れると、あんたのアプリケー
ションが動かなくなるだけですよ。くらいの感じです。

デメリットは、 XCube の「なるたけ型安全」に逆行する考えであるということ。

それと、仮想サービスはバーチャルとはいえサービス/クライアント型ですので、
バージョンアップや同名互換候補と交換した場合などで、メソッドの欠損が生ま
れた場合もクライアントがうまく処理してくれる(フェータルエラーにならない)
のですが、
直接オブジェクトをやりとりすると、バージョンの違いやブランチの違いでフェー
タルエラーに遭遇する可能性が高いことです。

個人的には、
XOOPS Cube はあくまで一種のコンストラクションツールであって、
「サイトオーナーがビルドに関わる」
「サイトオーナーの手元で組み合わせが完成して、初めてコンパイル」
だと思っているので、仮想サービスのほうが向いているだろうと思っています。

他方、そんなアレな事態は滅多にないことを考えると、
setService($tag, $service), getService($tag) で直接オブジェクトやりとりしても
ええがね!
特に、技術者がプログラムを付け足しながら1サイト作る場合なんか、XMLサー
ビス作ってもしょうがないので、これでええがね!というのも、あると思います。


個人的には、
まぁいまは仮想サービスは完成していないので使われないのは当然として、
今後モジュール間通信というか、アドオンによるCMSのAPI拡張手段として、
仮想サービスが想定通り使われていくのかどうか、
あるいは、面倒なのでオブジェクト直預けのほうが有効に活用してもらえるのか
測りかねており、ヒアリングのために、フォーラム/試験的実装する予定でもあり
ます。

--
minahito (mina...@gmail.com)

K. Ono

unread,
Jan 27, 2008, 12:01:23 AM1/27/08
to xcube-...@googlegroups.com
onokazuです。

> それで(話が変わっていくのですが)
> 7月を予定しているメジャーバージョンで、
> 従来、コアによって定義されていた数個のマネージャークラスとは別に、
> 自由なオブジェクトをルートに預けておける機能をつけてはどうかという
> アイデアを出しています。
>
> http://sourceforge.net/forum/forum.php?thread_id=1919905&forum_id=537172
>
> この場合、カテゴリモジュールのプリロードでカテゴリサービスのオブジェ
> クトを作ってルートに預け、使う側はルートから取り出して使います。
>
> メリットは、仮想サービスより直感的だということ。
> ほぼ、グローバル変数の世界です。
> 狂った仕様のようですが、

これは全然おかしくないと思います。Service LocatorやDIがこれと似たようなものではないでしょうか。

http://kakutani.com/trans/fowler/injection.html#ADynamicServiceLocator

あとは、Rootが、Rootに登録されているServiceについて、それらの依存性も解決してServiceを返すのか、
それとも単純にServiceを返すのかによって、DIまたはService Locatorのいずれかに
なるのではと思います。ただ、どちらにしてもその実装方法にはいろいろバリエーションが
考えられると思いますが。。

また、ちょっと関連していますが、今のところRootをgetSingleton()で取得したり、またはXCube_Controllerの
$mRootで取得したりと、Rootの取得方法が統一されていないみたいですが、これは統一される予定は
ないでしょうか。getSingleton()で取得するのであれば、流し込んだコントローラの$mRootからアクセス可能に
する必要はないと思いますし、流し込んだコントローラの$mRootから常にアクセスするのであれば、
getSingleton()は不要なのではないかと思います。個人的には、$mRootとして常に流し込んでいけるのであれば、
そちらにした方がよいのではないかと。。getSingleton()の方法だと、どんなに深い所からでも全てのサービスに
アクセスできてしまうので、少し危険なような感じがします。getSingletonがあるのはレガシー対策のためでしょうか?それであれば納得できますが。。

K. Ono

unread,
Jan 27, 2008, 12:06:24 AM1/27/08
to xcube-...@googlegroups.com
onokazuです

> http://kakutani.com/trans/fowler/injection.html#ADynamicServiceLocator

すいません、リンク先まちがってました(google検索結果をコピペしたので^^;)。

http://kakutani.com/trans/fowler/injection.html

また、sitepoint.comのフォーラムでServiceLocatorとDIに関する議論がたくさんあります。

HIKAWA Kilica

unread,
Jan 28, 2008, 9:16:53 AM1/28/08
to xcube-...@googlegroups.com
氷川です。

伊藤さん、minahitoさん、onokazuさん、アドバイスありがとうございます。

Delegate もまだもたもた使っているレベルですし、仮想サービスはなんとな

分かったような分からないような、という感じです(^ ^;
まずは通常の登録・表示関係のところから着手して、その間に調べながら
作っていこうかと思います。

なお、2,3ヶ月ほど、忙しくなりそうなので、進みは遅いと思います。
以上です。

minahito

unread,
Feb 2, 2008, 9:44:04 PM2/2/08
to xcube-...@googlegroups.com
minahito です。

> これは全然おかしくないと思います。Service LocatorやDIがこれと似たようなものではないでしょうか。

型解決の責任がすべて呼び出し側にあるので、この方法だと DI には及ばない
感じです。たとえば .NET の一部にある、

"なんとかかんとかManager"

という名前で、「グラフィックデバイスインターフェイスをやりとりする」と
いう規約は、あくまで人間様の縛りであって、 Object * まで抽象化するので、
適当なクラスのインスタンスを預ければ一発でアプリケーションが落ちます。

ただリアルタイムアプリケーション用のフレームワークで実装されているもの
なので、マイクロソフト的には、
「数ナノ秒を争ってるときに型解決なんかやっていられるか」
という感じなんだと思います。

まぁ確かに「かっこ悪い」以外の実害はないですし、
リアルタイムの世界だと「速いかどうか」ですしね。

とはいえ、ユーザーが作った独自型をやりとりするならともかく、
グラフィックデバイスマネージャーなどのハードウェアデバイスまで一旦、
型情報を消滅させるのには驚きました。

# 詳しくないのですが、ひょっとしたら Object * レベルまで抽象化しても、
# .NET なら RTTI で型確認ができるのかもしれません。
# それで例外で落としているのかも。


Cube で void* や object* がいやだなぁと思っているのは、
DelegateManager などの場合は、少なくとも XCube_DelegateManager
クラスがコアにあるため、最低限の型情報をチェックできるのですが、
setService/getService でやりとりをする場合、アドオン側でアドオン
のサービスの型が確定できない
(kilica 製 CategoryManager と minahito 製 CategoryManager の絶
対定義が存在しない)
ため、型を見ずにやるしかありません。

たぶん使う側は、ちゃんとやろうとするなら method exist で逐一チェッ
クしながら使わないといけません。仮想サービスならこれがクライア
ントのクラスに備わっています。

でも実際はたぶん void * 的なやりとりで全然問題ないでしょうね。
そっちのほうがモジュールAPI放出がうまく進んでニギヤカになるなら
それを選択するのが XOOPS だと思いますし。

> あとは、Rootが、Rootに登録されているServiceについて、それらの依存性も解決してServiceを返すのか、
> それとも単純にServiceを返すのかによって、DIまたはService Locatorのいずれかに
> なるのではと思います。

DI はひとつの手だと思います。
ただ、今回のテーマは「仮想サービスは書けば外部サイトに送信できるが、
手順が必要で、しかも重い」というものなので、 void * 抽象化案に DI を使
う事で、
「setService/getService はオブジェクトをやりとりするだけだが、手順が必
要で、しかも重い」
ってならないようにする必要があるので、Service Locator のほうになるので
しょうか。
(Service Locator を知らないんですが...)


$categoryMgr = $root->getService<CategoryManager>("CategoryManager");

的な感覚で済む話だし、あんまし上で書いたほどの問題ではないかもしれな
いですね。。


> また、ちょっと関連していますが、今のところRootをgetSingleton()で取得したり、またはXCube_Controllerの
> $mRootで取得したりと、Rootの取得方法が統一されていないみたいですが、これは統一される予定は
> ないでしょうか。getSingleton()で取得するのであれば、流し込んだコントローラの$mRootからアクセス可能に
> する必要はないと思いますし、流し込んだコントローラの$mRootから常にアクセスするのであれば、
> getSingleton()は不要なのではないかと思います。

どちらかというと、 XCube_Root::getSingleton() のほうです。
XCube_Root はシングルトンですから、どこで取ろうが同じオブジェクトを
見ている(2つのオブジェクトが生成されない)ので、どこを見ても構わな
いのですが、どうしても統一をかける必要があるなら、
XCube_Root::getSingleton() で統一をかける必要があるかと。

メンバでとってる場合はメンバを見てもいいと思います。速いし...

getSingleton() の要/不要は、 XCube_Root がシングルトンかどうか、によっ
てのみ決定すると思いますので、 getSingleton をつぶすのはまずいと思いま
す。

# まぁ実際にはコンストラクタの隠蔽まではやってませんが...
# PHP4 だとそもそもできないけど...

いずれにせよ、タスクシステムを入れると XCube_Controller は無くさざるを
えないので、原則 XCube_Root::getSingleton() のほうが窓口になっていくと
思います。


> getSingleton()の方法だと、どんなに深い所からでも全てのサービスに
> アクセスできてしまうので、少し危険なような感じがします。

個人的には、
BASE またぎをさせようと思うと、むしろ BASE の規定する「深さ」によ
らず、共通項となる Cube にアクセスできなければ始まらないと思ってい
ます。

ちなみに、
最初から悪意をもった破壊目的のコード以外で、
XCube_Root::getSingleton() があることによる危険って具体的にどういった
コードになるのでしょうか?

--
minahito (mina...@gmail.com)

K. Ono

unread,
Feb 3, 2008, 3:42:10 AM2/3/08
to xcube-...@googlegroups.com
onokazuです。

> Cube で void* や object* がいやだなぁと思っているのは、
> DelegateManager などの場合は、少なくとも XCube_DelegateManager
> クラスがコアにあるため、最低限の型情報をチェックできるのですが、
> setService/getService でやりとりをする場合、アドオン側でアドオン
> のサービスの型が確定できない
> (kilica 製 CategoryManager と minahito 製 CategoryManager の絶
> 対定義が存在しない)
> ため、型を見ずにやるしかありません。
>
> たぶん使う側は、ちゃんとやろうとするなら method exist で逐一チェッ
> クしながら使わないといけません。仮想サービスならこれがクライア
> ントのクラスに備わっています。

いずれにせよ、PHP4だと、どこかで手動チェックが必要になるかと思いますが。。
どうしても厳密な型チェックが必要ということであれば、minahitoさんの言われる
「アドオン」側にもそのような機能をつけておくこともできないでしょうか。
例えば、

class XCube_Controller
{
  var $_subSystemsToUse;

  function XCube_Controller($subSystemsToUse)
  {
   $this->_subSystemsToUse = $subSystemsToUse;
  }

  function prepare(&$root)
  {
   foreach ((array)$this->_subSystemsToUse as $sub_system_name =>
$sub_system_type) {
    $sub_system =& $root->getService($sub_system_name);
    if (!is_subclass_of($sub_system, $sub_system_type)) {
     trigger_error('Fatal error', E_USER_ERROR);
    }
    $this->_{$sub_system_name} =& $sub_system;
   }
 }
}

class My_Controller extends XCube_Controller
{
 var $_DelegateManager;
 var $_CategoryManager;

 function My_Controller()
 {
  parent::XCube_Controller(array('DelegateManager' =>
'XCube_DeletegateManager', 'CategoryManager' => 'MyCategoryManager'));
 }
}

ただ、これはアドオン側が、事前に自身が必要なサブシステムは何かを把握して
いる必要はありますが。。
ただし、このようなチェック機構を設けても、XCube_Root::getSingleton()で
いつでもどこからでも全てのサブシステムへとアクセスできてしまうと、この
チェック機構の意味がなくなります。これがgetSingleton()の危険性の一つ
じゃないかなあと思います。


> 「setService/getService はオブジェクトをやりとりするだけだが、手順が必
> 要で、しかも重い」
> ってならないようにする必要があるので、Service Locator のほうになるので
> しょうか。
> (Service Locator を知らないんですが...)

Service Locatorパターンですが、多分もともとはJavaから来たものだと思います。
僕自身も初めて見たのがX2開発前に「Core J2EE Patterns」という本を読んだ時
で、その時はそのパターンの重要性がほとんど分かっていませんでした。

ただ、今いろんな所で言われているService LocatorパターンはMartin Fowler氏
提唱のものだと思います。同氏提唱のRegistryパターンとあまり変わらないと
思いますが、名前の通り「サービスを探し出してくる」役割を持つ特別な
Registryのようなものと捉えています。


> ちなみに、
> 最初から悪意をもった破壊目的のコード以外で、
> XCube_Root::getSingleton() があることによる危険って具体的にどういった
> コードになるのでしょうか?

イメージ的には、例えばある企業の社員がアルバイトA君に顧客情報のデータ入力
を頼んだとして、「ネットにアクセスできないコンピュータ1を使ってくれ」と
言ったとします。それにも関わらず、部屋にはネットへとアクセスできる
コンピュータ2があって、A君はそのコンピュータ2を使用して作業を行って
しまった。その作業中に、何らかの操作でネットからウィルスがコンピュータ2
に入ってしまい、その結果、顧客情報がネットに流出してしまった。そのような
感じでしょうか。始めから例えばコンピュータ1しか置いてない部屋でA君に作業
させる(人間様の縛りだけではなく、物理的に縛る)とかしていればそのような
ことはなかったと思います。

XCでもう少し具体的に言えば、XCube_HttpRequestのgetRequest()を使用して
ユーザからの入力値を取得して欲しいのに、直接$_REQUESTを参照してしまう
ような感じです(この場合、$_REQUESTを参照してしまうこと自体は
防げませんが)。

クライアント(minahitoさんの言い方ではアドオン?)やデリゲートはいつでも
どこからでもグローバルなサブシステムにアクセスできてしまう(XCube_Root
およびそこから参照可能な全てのサブシステムに依存してしまう)ため、適切な
制限をかけにくくなるんじゃないかなと。。

例えばXiggではプラグインを第3者に開発してもらうことを期待していますが、
プラグイン側からはアクセスして欲しくないリソースは、できるだけそのルート
は遮断してしまうようにしています。

そこまで深く考えなくても良いのかもしれませんが。。また、純粋に単一の
インスタンスを生成させることを目的に使用するのであれば、それに対しては
もちろん何ら疑問はありませんが、XCubeではそのインスタンスの取得に2つ
のルートがあったので、ちょっと質問させていただきました。

#X2でもSingleton多用していますが、当時流行っていたのと、X2はもう何年も
前のコードですので。。^^;

Reply all
Reply to author
Forward
0 new messages