コンテンツにスキップ

XOOPS アーキテクチャ

このドキュメントはXOOPSシステムアーキテクチャの包括的な概要を提供し、さまざまなコンポーネントがどのように連携して柔軟で拡張可能なコンテンツ管理システムを作成するかを説明しています。

XOOPSはモジュラーアーキテクチャに従い、懸念事項を異なるレイヤーに分離します。システムはいくつかのコア原則を中心に構築されています:

  • モジュール性: 機能は独立した、インストール可能なモジュールに編成されています
  • 拡張性: コアコードを変更せずにシステムを拡張できます
  • 抽象化: データベースとプレゼンテーションレイヤーはビジネスロジックから抽象化されています
  • セキュリティ: 一般的な脆弱性から保護する組み込みセキュリティメカニズム
graph TB
subgraph Presentation["🎨 Presentation Layer"]
Themes["Themes"]
Templates["Smarty Templates"]
Blocks["Blocks"]
end
subgraph Application["⚙️ Application Layer"]
Modules["Modules"]
Preloads["Preloads"]
Controllers["Controllers"]
BlockHandlers["Block Handlers"]
end
subgraph Domain["📦 Domain Layer"]
XoopsObject["XoopsObject"]
Handlers["Object Handlers"]
Criteria["Criteria System"]
end
subgraph Infrastructure["🔧 Infrastructure Layer"]
Database["XoopsDatabase"]
Cache["Cache System"]
Session["Session Manager"]
Security["Security Layer"]
end
Presentation --> Application
Application --> Domain
Domain --> Infrastructure
style Presentation fill:#e8f5e9,stroke:#388e3c
style Application fill:#e3f2fd,stroke:#1976d2
style Domain fill:#fff3e0,stroke:#f57c00
style Infrastructure fill:#fce4ec,stroke:#c2185b

1. プレゼンテーションレイヤー

Section titled “1. プレゼンテーションレイヤー”

プレゼンテーションレイヤーはSmartyテンプレートエンジンを使用したユーザーインターフェイスレンダリングを処理します。

主要コンポーネント:

  • Themes: ビジュアルスタイルとレイアウト
  • Smarty Templates: 動的なコンテンツレンダリング
  • Blocks: 再利用可能なコンテンツウィジェット

アプリケーションレイヤーは、ビジネスロジック、コントローラー、モジュール機能を含みます。

主要コンポーネント:

  • Modules: 自己完結した機能パッケージ
  • Handlers: データ操作クラス
  • Preloads: イベントリスナーとフック

ドメインレイヤーはコアビジネスオブジェクトと規則を含みます。

主要コンポーネント:

  • XoopsObject: すべてのドメインオブジェクトの基本クラス
  • Handlers: ドメインオブジェクトのCRUD操作

4. インフラストラクチャレイヤー

Section titled “4. インフラストラクチャレイヤー”

インフラストラクチャレイヤーはデータベースアクセスやキャッシングなどのコアサービスを提供します。

リクエストライフサイクルを理解することは、XOOPS開発を効果的に行うために重要です。

XOOPS 2.5.x ページコントローラーフロー

Section titled “XOOPS 2.5.x ページコントローラーフロー”

現在のXOOPS 2.5.xはページコントローラーパターンを使用します。このパターンでは、各PHPファイルが自身のリクエストを処理します。グローバル($xoopsDB$xoopsUser$xoopsTplなど)はブートストラップ中に初期化され、実行全体で利用可能です。

sequenceDiagram
participant Browser
participant Entry as modules/mymod/index.php
participant Main as mainfile.php
participant Kernel as XOOPS Kernel
participant DB as $xoopsDB
participant User as $xoopsUser
participant Handler as MyObjectHandler
participant Tpl as $xoopsTpl (Smarty)
participant Theme
Browser->>Entry: GET /modules/mymod/index.php
rect rgb(240, 248, 255)
Note over Entry,User: Bootstrap Phase (mainfile.php)
Entry->>Main: include mainfile.php
Main->>Kernel: Initialize Core
Kernel->>DB: Create XoopsDatabase (singleton)
Kernel->>User: Load Session → $xoopsUser
Kernel->>Tpl: Initialize Smarty → $xoopsTpl
Main-->>Entry: Globals Ready
end
rect rgb(255, 250, 240)
Note over Entry,Handler: Page Controller Execution
Entry->>Handler: xoops_getModuleHandler('myobject')
Handler->>DB: query via Criteria
DB-->>Handler: Result Set
Handler-->>Entry: XoopsObject[]
end
rect rgb(240, 255, 240)
Note over Entry,Theme: Rendering Phase
Entry->>Tpl: $xoopsTpl->assign('items', $objects)
Entry->>Theme: include header.php
Entry->>Tpl: $xoopsTpl->display('mymod_index.tpl')
Entry->>Theme: include footer.php
Theme-->>Browser: Complete HTML Page
end
グローバル初期化目的
$xoopsDBXoopsDatabaseブートストラップデータベース接続(シングルトン)
$xoopsUserXoopsUser|nullセッション読み込み現在ログインしているユーザー
$xoopsTplXoopsTplテンプレート初期化Smartyテンプレートエンジン
$xoopsModuleXoopsModuleモジュール読み込み現在のモジュールコンテキスト
$xoopsConfigarray設定読み込みシステム設定
// mainfile.phpはエントリーポイントです
include_once XOOPS_ROOT_PATH . '/mainfile.php';
// コア初期化
$xoops = Xoops::getInstance();
$xoops->boot();

ステップ:

  1. 設定を読み込む(mainfile.php
  2. オートローダーを初期化
  3. エラーハンドリングを設定
  4. データベース接続を確立
  5. ユーザーセッションを読み込む
  6. Smartyテンプレートエンジンを初期化
// 適切なモジュールへのリクエストルーティング
$module = $GLOBALS['xoopsModule'];
$controller = $module->getController();
$controller->dispatch($request);

ステップ:

  1. リクエストURLを解析
  2. ターゲットモジュールを特定
  3. モジュール設定を読み込む
  4. パーミッションをチェック
  5. 適切なハンドラーにルート
// コントローラー実行
$data = $handler->getObjects($criteria);
$xoopsTpl->assign('items', $data);

ステップ:

  1. コントローラーロジックを実行
  2. データレイヤーと相互作用
  3. ビジネスルールを処理
  4. ビューデータを準備
// テンプレートレンダリング
include XOOPS_ROOT_PATH . '/header.php';
$xoopsTpl->display('db:module_template.tpl');
include XOOPS_ROOT_PATH . '/footer.php';

ステップ:

  1. テーマレイアウトを適用
  2. モジュールテンプレートをレンダリング
  3. ブロックを処理
  4. レスポンスを出力

XOOPSのすべてのデータオブジェクトの基本クラスです。

<?php
class MyModuleItem extends XoopsObject
{
public function __construct()
{
$this->initVar('id', XOBJ_DTYPE_INT, null, false);
$this->initVar('title', XOBJ_DTYPE_TXTBOX, '', true, 255);
$this->initVar('content', XOBJ_DTYPE_TXTAREA, '', false);
$this->initVar('created', XOBJ_DTYPE_INT, time(), false);
}
}

主要メソッド:

  • initVar() - オブジェクトプロパティを定義
  • getVar() - プロパティ値を取得
  • setVar() - プロパティ値を設定
  • assignVars() - 配列から一括割り当て

XoopsObjectインスタンスのCRUD操作を処理します。

<?php
class MyModuleItemHandler extends XoopsPersistableObjectHandler
{
public function __construct(\XoopsDatabase $db)
{
parent::__construct($db, 'mymodule_items', 'MyModuleItem', 'id', 'title');
}
public function getActiveItems($limit = 10)
{
$criteria = new CriteriaCompo();
$criteria->add(new Criteria('status', 1));
$criteria->setSort('created');
$criteria->setOrder('DESC');
$criteria->setLimit($limit);
return $this->getObjects($criteria);
}
}

主要メソッド:

  • create() - 新しいオブジェクトインスタンスを作成
  • get() - IDでオブジェクトを取得
  • insert() - オブジェクトをデータベースに保存
  • delete() - データベースからオブジェクトを削除
  • getObjects() - 複数のオブジェクトを取得
  • getCount() - マッチするオブジェクトの数をカウント

すべてのXOOPSモジュールは標準的なディレクトリ構造に従います:

modules/mymodule/
├── class/ # PHPクラス
│ ├── MyModuleItem.php
│ └── MyModuleItemHandler.php
├── include/ # インクルードファイル
│ ├── common.php
│ └── functions.php
├── templates/ # Smartyテンプレート
│ ├── mymodule_index.tpl
│ └── mymodule_item.tpl
├── admin/ # 管理者エリア
│ ├── index.php
│ └── menu.php
├── language/ # 翻訳
│ └── english/
│ ├── main.php
│ └── modinfo.php
├── sql/ # データベーススキーマ
│ └── mysql.sql
├── xoops_version.php # モジュール情報
├── index.php # モジュールエントリー
└── header.php # モジュールヘッダー

最新のXOOPS開発では、より良いテスト性のために依存性注入を活用できます。

<?php
class XoopsDependencyContainer
{
private array $services = [];
public function register(string $name, callable $factory): void
{
$this->services[$name] = $factory;
}
public function resolve(string $name): mixed
{
if (!isset($this->services[$name])) {
throw new \InvalidArgumentException("Service not found: $name");
}
$factory = $this->services[$name];
if (is_callable($factory)) {
return $factory($this);
}
return $factory;
}
public function has(string $name): bool
{
return isset($this->services[$name]);
}
}
<?php
namespace Xmf\Di;
use Psr\Container\ContainerInterface;
class BasicContainer implements ContainerInterface
{
protected array $definitions = [];
public function set(string $id, mixed $value): void
{
$this->definitions[$id] = $value;
}
public function get(string $id): mixed
{
if (!$this->has($id)) {
throw new \InvalidArgumentException("Service not found: $id");
}
$entry = $this->definitions[$id];
if (is_callable($entry)) {
return $entry($this);
}
return $entry;
}
public function has(string $id): bool
{
return isset($this->definitions[$id]);
}
}
<?php
// サービス登録
$container = new XoopsDependencyContainer();
$container->register('database', function () {
return XoopsDatabaseFactory::getDatabaseConnection();
});
$container->register('userHandler', function ($c) {
return new XoopsUserHandler($c->resolve('database'));
});
// サービス解決
$userHandler = $container->resolve('userHandler');
$user = $userHandler->get($userId);

XOOPSは複数の拡張メカニズムを提供しています:

プリロードはモジュールがコアイベントをフックすることを許可します。

modules/mymodule/preloads/core.php
<?php
class MymoduleCorePreload extends XoopsPreloadItem
{
public static function eventCoreHeaderEnd($args)
{
// ヘッダー処理が終了したときに実行
}
public static function eventCoreFooterStart($args)
{
// フッター処理が開始したときに実行
}
}

プラグインはモジュール内の特定の機能を拡張します。

modules/mymodule/plugins/notify.php
<?php
class MymoduleNotifyPlugin
{
public function onItemCreate($item)
{
// アイテムが作成されたときに通知を送信
}
}

フィルターはシステムを通過するデータを変更します。

<?php
// コンテンツフィルターの例
$myts = MyTextSanitizer::getInstance();
$content = $myts->displayTarea($rawContent, 1, 1, 1);
  1. 新しいコードにはネームスペースを使用:

    namespace XoopsModules\MyModule;
    class Item extends \XoopsObject
    {
    // 実装
    }
  2. PSR-4オートローディングに従う:

    {
    "autoload": {
    "psr-4": {
    "XoopsModules\\MyModule\\": "class/"
    }
    }
    }
  3. 関心事を分離:

    • class/内のドメインロジック
    • templates/内のプレゼンテーション
    • モジュールルート内のコントローラー
  1. 高コストな操作にはキャッシングを使用
  2. 可能な限りリソースを遅延読み込み
  3. クライテリアバッチ処理を使用してデータベースクエリを最小化
  4. 複雑なロジックを避けてテンプレートを最適化
  1. Xmf\Requestを使用してすべての入力を検証
  2. テンプレートで出力をエスケープ
  3. データベースクエリにプリペアドステートメントを使用
  4. 機密操作の前にパーミッションをチェック

#xoops #architecture #core #design #system-design