プロフェッショナルなウェブサイト

このデモについて

学術的MVCからプロフェッショナルなWebアーキテクチャへ

学術的MVCからプロフェッショナルなWebアーキテクチャへ
💡 プロフェッショナルとは:理解可能、テスト可能、拡張可能、安全に構造化された

長期プロジェクト基盤としてのモジュール式ミニフレームワークの開発

目標

このプロジェクトは、スケーラブルなWebアプリケーション開発のためのアーキテクチャリファレンスとして機能します。学術的MVC構造からプロフェッショナルでモジュール式のWebアーキテクチャへの段階的な移行を示しています。

最終結果は単一のプロジェクトではなく、軽量なミニフレームワークであり、以下の特徴を持ちます:

  • 理解可能、テスト可能、拡張可能、安全に構造化されています。
  • 任意のWebプロジェクトの安定した基盤として機能します
  • 後日の完全なリファクタリングを回避します

「適切なシャーシを一度構築する – その後はモジュールを交換するだけ」

出発点

いくつかの既に実装されたデモプロジェクトが基礎として機能します(MVC、セッション、ログイン、モジュール式CSSなど)。

これらのプロジェクトは機能的に適切に構築されていますが、関数に大きく依存しており、主に小規模アプリケーションに適しています。プロジェクトサイズが増大すると、構造、保守性、拡張性の点で限界に達します。

この移行を制御するために、2つのプロジェクトを作成しました。2つのフェーズと言えます:

  • フェーズ1: 古典的な学術的MVCプロジェクトの拡張
  • フェーズ2: デモログインプロジェクトのプロフェッショナル化と次のレベルへの引き上げ

ステージ

👉 各ステージは独立して機能します
👉 「すべてやり直し」の瞬間はありません

ステージ焦点目標フェーズ
1 学術的MVC 理解(出発点)1
2 フォルダ構造 & サービス責任の分離 & 概要 1
3インデックスの軽減 & リクエストフローブートストラップ & ルーター1
4 .htaccess設定アクセスセキュリティ(基礎) 1
5 フェーズ2の調整モジュール性 & 保守性 2
6 モジュール式CSS保守性 & スケーラビリティ 2
7 クラス & ナビゲーション 構造 & テスト容易性2
8 ミニフレームワーク長期的基盤2

この表は、単純な概念からプロフェッショナルなアーキテクチャへの構造化された移行を示しています。

構造

目標: リファクタリングなしで、責任の分離、セキュリティ、明瞭さを実現

原則: public/のみが公開アクセス可能 – それ以外はすべて保護されています。

10_Professional_web/
 ├─ app/
 │  ├─ config/
 │  ├─ control/
 │  ├─ helper/
 │  ├─ model/
 │  ├─ router/
 │  ├─ security/
 │  ├─ service/
 │  ├─ view/
 │  └─ bootstrap.php
 │  └─ router.php
 │  └─ session.php
 ├─ doc/...
 ├─ public/          ← 唯一の公開領域
 │  ├─ css/
 │  └─ img/
 │  ├─ js/
 │  ├─ index.php     ← シングルエントリーポイント
 ├─ sql/
 ├─ storage/
 │  ├─ logs/
 │  └─ upload/
 └─ README.md

インデックスの軽減

問題

学術的MVCでは、index.phpが多くのタスクを引き受けます:

  • ルーター
  • コントローラー
  • セキュリティゲート
  • ワークフローオーケストレーター

👉 混沌の単一点

目標

index.phpは以下になります:

  • 開始点
  • ロジックなし

解決策

  • ルーターの外部化
  • 中央ブートストラップロジック
  • オートローディングの準備
  • 明確なリクエストパイプライン

リクエストパイプライン

リクエストpublic/index.phpブートストラップルーターコントローラーサービスビュー / レスポンス

ブートストラップ

初期化します:

  • 設定
  • セッション
  • ヘルパー
  • コントローラー & サービス
  • モデル & ビュー

ルーター

タスク:

  • URL → コントローラー / アクション
  • パラメータの抽出
  • エラーの適切な処理

実装

  • 作成:app/bootstrap.php
  • インデックスから新しいブートストラップへのインポートパスの移動
  • switch($page)をコントローラー内の関数に埋め込んで移動
  • コントローラーコンテンツをサービスフォルダに移動し、新しいファイルに分散:
App/services/
 │  ├─ AuthService.php
 │  ├─ UserService.php
 │  ├─ ProfileService.php
 │  ├─ SessionService.php
 │  └─ UploadService.php
  • 作成:app/router.php
  • 言語およびページチェックをsession.phpからrouter.phpに移動

.htaccessによる安全なアクセス

2ファイルアーキテクチャ

アクセス制御には、.htaccessを使用した2ファイルアーキテクチャが採用されています。ルートディレクトリ内のファイルは外部アクセスを制御し、リクエストをpublicフォルダに具体的に誘導します。publicディレクトリ内の.htaccessはアプリケーションマウントを担当します。

この分離により、多層セキュリティコンセプト、明確な責任分担、そしてより良い保守性が確保されます。

フェーズ2の調整

フェーズ2は、既存のアーキテクチャを成長、複雑化の増大、クリーンなリソース管理に向けて計画的に準備することを目的としています。

設定の分割

app/config/
├── config.php # メイン設定
├── app/ # アプリケーション設定
│    ├── form.config.php # フォーム設定
│    └── app.config.php # アプリケーション設定
└── domain/ # ドメイン固有設定
│    ├── page.config.php # ページ設定
│    └── user.config.php # ユーザー管理設定
└── security/ # セキュリティのプレースホルダー
  • 🎯 ターゲットローディング:必要な設定のみをロード
  • 📁 より良い組織化:主題別グループ化
  • 🧩 モジュール性:サービスへの簡単な統合

モジュール式CSS

次のステップでは、モジュール式CSSがプロジェクトに統合されました。既存のデモプロジェクトが基礎として機能し、最小限の労力で採用され、app/css/ディレクトリに挿入されました。既存の構造はその後、残りのアーキテクチャに適切に統合されるようにわずかに調整・最適化されました。

モジュール式CSSをアプリケーションにプロフェッショナルに統合するために、スタイルはApp領域から直接提供されません。代わりに、CSSはpublic/css/ディレクトリで動的に生成されます。これにより、クラシックなスタイルシートのようにヘッダーに含めることができます:

<link rel="stylesheet" href="css/style.php?page=<?php echo htmlspecialchars($_SESSION[S_PAGE]); ?>">

style.phpファイルは制御されたエントリーポイントとして機能します。内部CSSモジュールをインクルードし、内部ファイルへの直接アクセスを防止し、CSSが正しくスタイルシートとして提供されることを保証します。さらに、望ましくないキャッシュが防止され、変更が即座に反映されます:

// インクルードファイルへの直接アクセスを防止するためのセキュリティ定数の定義
define("SECURE_INCLUDE", true);

// CSSメインファイルのインクルード
require_once __DIR__ . "/../../app/css/main.css.php";

// ファイルをCSSとして宣言し、キャッシュを防止
header("Content-Type: text/css; charset=UTF-8");
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Pragma: no-cache");
header("X-Content-Type-Options: nosniff");

// GETパラメータによるページの決定
$page = $_GET["page"] ?? "index";
if (!in_array($page, P_LIST, true)) {
    $page = "index";
}

echo generateCSS(renderCSS($page));

このソリューションは、モジュール式CSSの利点と、内部構造と公開配信の明確な分離を組み合わせ、既存のプロジェクトアーキテクチャにシームレスに統合されます。

クラス

クラスは、明確な付加価値を提供するプロジェクト内で使用されます。これには、関連するロジックを持つ共有データ、より複雑な依存関係、およびテスト容易性と拡張性が重要な領域が含まれます。すべての関数が必ずしもクラスに変換されるわけではありません。

ビューは純粋なテンプレートのまま維持され、単純なヘルパーは意図的に関数として残すことができます。

セッション

セッションロジックは完全に独自のクラスに外部化されました。これには、cSessionクラスが作成され、セッションの開始と基本的な初期化を中央で処理します:

class cSession {
    public static function start(): void {

        session_start();

        self::initDefaults();
        self::initCsrfToken();
        self::sanitizeSession();
    }
    // およびこれらの関数が作成されました:
    initDefaults
    initCsrfToken
    sanitizeSession
    requireAccess
    isGuest
    getRole
    getUserId
    increaseLoginAttempts
    isRateLimited

check_user_access関数はSessionクラスから削除され、AuthServiceに移動されました。セッション開始時のロールチェックも認証領域に外部化され、auth_init関数にまとめられ、ブートストラップで中央呼び出しされます。

さらに、AdminServiceが導入されました。編集可能なユーザーのチェックはセッションから削除され、独自のset_edit_user_id関数にカプセル化され、これもブートストラップの開始時に実行されます。

再構築の過程で、関数呼び出しが標準化されました。例えば、handleSessionTimer()からcSession::increaseLoginAttempts()へ、およびisSessionLimited()からisRateLimited()へ。最後に、古いファイルが削除され、具体的にはappディレクトリ内のsession.phpおよびService領域内のsession_service.phpが削除されました。

ルーター

ルーターも独自のクラスに外部化されました。cRouterクラスはルーティングの中央初期化を処理し、言語とページの認識を担当します:

class cRouter {
    public static function init(): void {
        self::resolveLanguage();
        self::resolvePage();
    }
}

以前の言語およびページ認識ロジックはSessionコンテキストから削除され、ルーター内の2つの明確に分離された関数に転送されました。これにより、ルーティングの責任は完全にルーターにあり、Sessionクラスは本来のタスクに集中します。

データベース

データベース接続のために、定期的なタスクをバンドルし、データベースとの対話を簡素化する汎用クラスが作成されました。cDatabaseクラスは、接続の確立および頻繁に必要なクエリと実行操作をカプセル化します:

class cDatabase {
    private static ?PDO $dbh = null;
    public static function getConnection(): PDO {…}
    public static function close(): void {…}
    public static function fetchAll(…): array {…    }
    public static function fetchOne(…): array|false {…}
    public static function execute(…): bool {…}
}

この中央抽象化により、データベースアクセスが統一されて実装され、定期的なロジックが一度だけ実装される必要があるため、既存の関数が簡素化されます。追加の一貫性アプローチにより、保守性が向上し、エラー源が減少し、拡張のための安定した基盤が形成されます。

ナビゲーション

問題

以下に応じた異なるナビゲーション:

  • ページ
  • ユーザーロール
  • ログイン状態

解決策

  • 各ページに対して許可されたロールを定義
  • ページの可視性は中央ルールで制御
  • フィルター関数で散在するif文を置き換え

実装

まず、中央Security-Configファイルが作成されました。これにより、各ページのセキュリティルールとアクセス権限を定義する定数テーブルが定義されます。以前のページ固有のコントローラーチェックは削除され、ページ処理の開始時の単一の中央チェックに置き換えられました。これにより、ロジックがより明確になり、冗長なチェックがなくなります。

その後、スタンドアロンで呼び出し可能なルートファイルが導入されました。このファイルは、以前のルートコントローラのswitchロジックを置き換える配列を返します。ページはキーとして定義され、それぞれが以前のhandle*およびrenderView*呼び出しを含む匿名関数を参照します。適応後、元のswitchは完全に削除され、新しいルーティングが正常にロード、テスト、実行されました:

// ルートのロード(ルート → 呼び出し可能)
$routes = require CONTROL_DIR . 'routes.php';

// ルートが存在しない場合のフォールバック
if (!isset($routes[$page]) || !is_callable($routes[$page])) {
    errorLog(__FILE__, __LINE__, __FUNCTION__, "Unknown route: {$page}");
    reload_page(P_HOME);
}

// ルートの実行(コントローラーアクション)
$routes[$page]($labels);

さらに、定義されたセキュリティルールに基づいて、特定のページにリンクできるページのリストを自動的に決定する関数が実装されました。このリストはナビゲーションの基礎として機能します。既存のナビゲーションロジックはその後、改訂、簡素化され、現在は動的に生成されたナビゲーションリストのみを使用します。

ミニフレームワーク

以前に導入された概念を組み合わせることにより、元のMVCプロジェクトから軽量なミニフレームワークが生まれます。
ブートストラップ、ルーター、中央セキュリティルール、サービス層、モジュール式構成、および明確に分離された責任が一体となって安定したアーキテクチャを形成します。

このミニフレームワークは、大規模フレームワークを完全に置き換えるものではなく、独自のWebプロジェクトのための制御された理解可能な基盤として機能します。
クリーンな拡張を可能にし、後の構造的破壊を回避し、実証済みの基盤上での新しいアプリケーションを可能にします。

👉 このプロジェクトは、単一のアプリケーションで終わるのではなく、再利用可能なアーキテクチャで終わります。